线程间的经典操作案例——生产者与消费者案例

程序基本模型:

package Project.Study.Multithreading;class Message{private String title;   //保存信息的标题private String content; //保存信息的内容public void setTitle(String title) {this.title = title;}public void setContent(String content) {this.content = content;}public String getTitle() {return title;}public String getContent() {return content;}
}
class Producer implements Runnable{     //定义生产者private Message msg=null;public Producer(Message msg){this.msg=msg;}@Overridepublic void run(){for (int x=0;x<50;x++){              //生产50次数据if(x%2==0){this.msg.setTitle("小关");    //定义title属性try {Thread.sleep(100);      //延迟操作}catch (InterruptedException e){e.printStackTrace();}this.msg.setContent("学习Java");//设置content属性}else{this.msg.setTitle("小梁");        //设置title属性try {Thread.sleep(100);          //延迟操作}catch (InterruptedException e){e.printStackTrace();}this.msg.setContent("学习python");//设置content属性}}}
}
class Consumer implements Runnable{private Message msg;public Consumer(Message msg){this.msg=msg;}@Overridepublic void run(){for(int x=0;x<50;x++){try{Thread.sleep(100);}catch (InterruptedException e){e.printStackTrace();}System.out.println(this.msg.getTitle()+"-->"+this.msg.getContent());}}
}
public class Test10 {public static void main(String []args){Message msg=new Message();new Thread(new Producer(msg)).start();new Thread(new Consumer(msg)).start();}
}
//结果:
//小梁-->学习Java
//小关-->学习python
//小梁-->学习Java
//小关-->学习python
//小梁-->学习Java
//小关-->学习python
//小梁-->学习Java
//小关-->学习python
//小梁-->学习Java
//(...)

本来上程序预期的输出结果是:小关–>学习Java,小梁–>学习python
但很明显出现了问题,设置的数据发生了错位、数据重复取出和重复设置。

解决数据错乱问题

数据错位完全是因为非同步的操作,所以应该使用同步处理。
例:加入同步,解决数据错乱问题

package Project.Study.Multithreading;class Message2{private String title;   //保存信息的标题private String content; //保存信息的内容public synchronized void set(String title,String content){this.title=title;try{Thread.sleep(100);}catch(InterruptedException e){e.printStackTrace();}this.content=content;}public synchronized void get(){try{Thread.sleep(100);}catch (InterruptedException e){e.printStackTrace();}System.out.println(this.title+"-->"+this.content);}
}
class Producer2 implements Runnable{private Message2 meg=null;public Producer2(Message2 msg){this.meg=msg;}@Overridepublic void run(){for(int x=0;x<20;x++){if(x%2==0){this.meg.set("小关","学习Java");}else{this.meg.set("小梁","学习Python");}}}
}
class Consumer2 implements Runnable{private Message2 msg=null;public Consumer2(Message2 msg){this.msg=msg;}@Overridepublic void run(){for (int x=0;x<20;x++){this.msg.get();}}
}
public class Test11 {public static void main(String []args)throws Exception{Message2 msg=new Message2();new Thread(new Producer2(msg)).start();new Thread(new Consumer2(msg)).start();}
}
//结果:
//小梁-->学习Python
//小梁-->学习Python
//小梁-->学习Python
//小梁-->学习Python
//(...)

上程序解决了数据错位问题,但还是有重复取出和重复设置的问题。

解决数据重复问题

Object类对多线程的支持

No. 方法 类型 描述
1 public final void wait() throws InterruptedException 普通 线程的等待
2 public final void notify() 普通 唤醒第一个等待线程
3 public final void notifyAll() 普通 唤醒全部等待线程

一般来说,所有等待的线程会按照顺序进行排列。
如果使用了notify()方法,则会唤醒第一个等待的线程执行;
如果使用了notifyAll()方法,则会唤醒所有的等待线程,哪个线程的优先级高,哪个线程就有可能先执行。

例:

package Project.Study.Multithreading;class Message3{private String title;private String content;private boolean flag=true;//flag==true:表示可以生产,但是不能拿走//flag==false:表示可以取走,但是不能生产public synchronized void set(String title,String content){if(this.flag==false){try {super.wait();                   //等待}catch (InterruptedException e){e.printStackTrace();}}this.title=title;try {Thread.sleep(100);}catch (InterruptedException e){e.printStackTrace();}this.content=content;this.flag=false;                        //已经生产完成,修改标志位super.notify();                         //唤醒等待线程}public synchronized void get(){if (this.flag==true){                   //未生产,不能取走try {               super.wait();                   //等待}catch (InterruptedException e){e.printStackTrace();}}try {Thread.sleep(100);}catch (InterruptedException e){e.printStackTrace();}System.out.println(this.title+"-->"+this.content);this.flag=true;                         //已经取走了,可以继续生产super.notify();                         //唤醒等待线程}
}
class Producer3 implements Runnable{private Message3 meg;public Producer3(Message3 msg){this.meg=msg;}@Overridepublic void run(){for(int x=0;x<10;x++){if(x%2==0){this.meg.set("小关","学习Java");}else{this.meg.set("小梁","学习Python");}}}
}
class Consumer3 implements Runnable{private Message3 msg;public Consumer3(Message3 msg){this.msg=msg;}@Overridepublic void run(){for (int x=0;x<10;x++){this.msg.get();}}
}public class Test12 {public static void main(String []args){Message3 msg=new Message3();new Thread(new Producer3(msg)).start();new Thread(new Consumer3(msg)).start();}
}
//结果:
//小关-->学习Java
//小梁-->学习Python
//小关-->学习Java
//小梁-->学习Python
//小关-->学习Java
//小梁-->学习Python
//小关-->学习Java
//小梁-->学习Python
//小关-->学习Java
//小梁-->学习Python

上程序解决了数据错位、数据重复取出和重复设置问题。

提示:
sleep()和wait()的区别:
1.sleep()是Thread类定义的static方法,表示线程休眠,将执行机会给其他线程,但是监控状态依然保持,会自动恢复;
2.wait()是Object类定义的方法,表示线程等待,一直到执行了notify()或notifyAll()后才结束等待。

Java学习总结:29相关推荐

  1. java学习(29):大神指导(巩固练习)

    /3使用Eclipse编写控制台应用程,使用do while循环处理从控制台接收不定数量的学生英语成绩, 统计不及格(小于60分)的成绩个数,大于等于90分的优秀成绩数量, 计算所有成绩的总分.平均分 ...

  2. Java学习笔记29(IO字符流,转换流)

    字符流:只能操作文本文件,与字节流的区别是,字节流是按照字节来读取文件,而字符流是按照字符来读取,因此字符流的局限性为文本文件 字符输出流:Write类,使用时通过子类   每一次写入都要刷新 pac ...

  3. Java学习笔记29

    ArrayList是List接口的实现类,支持List接口的全部功能,ArrayList类是基于数组实现的List类,在内部封装了一个动 态的.允许再分配的Object[]数组.ArrayList是线 ...

  4. Java入门1.2.3—一个老鸟的Java学习心得

    Java入门1.2.3-一个老鸟的Java学习心得 基本信息 作者: 臧萌    出版社:清华大学出版社 ISBN:9787302217831 上架时间:2010-3-30 出版日期:2010 年3月 ...

  5. java学习中,字符串使用(比较、构造方法)(java 学习中的小记录)

    java学习中,字符串使用(比较.构造方法)(java 学习中的小记录)作者:王可利(Star·星星) String的使用 1.在内存中是如何保存字符串. == :比较的是地址(引用数据类型) equ ...

  6. 【Java学习笔记之二十六】深入理解Java匿名内部类

    在[Java学习笔记之二十五]初步认知Java内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节问题,所以就衍生出这篇博客.在这篇博客中你可以了解到匿名内部类的使用.匿名内部类要注意 ...

  7. Java学习笔记22:并发(2)

    Java学习笔记22:并发(2) 图源:PHP中文网 终止任务 终止线程有一种非常简单的方式:设置一个多线程共享的标记位,子线程用轮询的方式检查这个标记位,如果该标记位显示取消状态,就让子线程退出执行 ...

  8. Java学习——Day13:IO流

    6.1 File类 java.io.File类:文件和文件目录路径的抽象表示形式,与平台无关 File 能新建.删除.重命名文件和目录,但 File 不能访问文件内容本身. 如果需要访问文件内容本身, ...

  9. 寒假宅喵java学习

    1.25 小fleeting 学习java 关于辅助书籍: Core Java 字典 比如学习完了IO的知识,觉得意犹未尽,那么就通过这本字典一样的Java书籍,把IO的知识更丰满的刷一遍 Effec ...

  10. java学习中,DVD管理系统纯代码(java 学习中的小记录)

    java学习中,DVD管理系统纯代码(java 学习中的小记录)作者:王可利(Star·星星) class DvdMain{public static void main (String[] args ...

最新文章

  1. 原生js获取document_【JS 口袋书】第 9 章:使用 JS 操作 HTML 元素
  2. androidstudio 日历视图怎么显示农历_中秋国庆旅游攻略怎么做?用这个便签软件很简单...
  3. 项目管理——文档的重要性
  4. 数据产品-规则型和挖掘型标签构建案例
  5. kubernetes-Deployment部署无状态服务的原理详解(七)
  6. iframe内容适应div大小_使用lt;iframegt;方式在WordPress中插入视频并自适应屏幕尺寸
  7. java多线程编程synchronized关键字
  8. java开发软件Myeclipse汉化教程
  9. 三菱plc和三菱E700变频器专用协议通讯程序
  10. 拼多多的砍价免费拿是真的吗?
  11. 【论文笔记】Semantic Parsing on Freebase from Question-Answer Pairs
  12. NuGet是什么?为什么.NET项目中会有NuGet?如何使用NuGet程序包?
  13. Windows 消息大全
  14. 最新美团-青龙——5-25
  15. elixir mix 简介
  16. 《C#高级编程第6版》 读书笔记 (张迅雷闪击C#系列)
  17. 13 Scrapy框架介绍
  18. linux有个很大的内存目录,Linux中的内存管理
  19. Create a Bootable 8G MicroSD Card for e-puck with wifi+webcam‏
  20. android显示通知图标大全,Android应用开发之android 桌面APP应用图标显示通知消息的数量显示与去除...

热门文章

  1. ATS日志格式中的Squid-和Netscape-格式的缓存结果码
  2. pip install失败报错解决方案
  3. 1042. 托普利兹矩阵
  4. numpy.random.seed()
  5. bzoj 1086: [SCOI2005]王室联邦
  6. SAP的安装后基本设定
  7. 解密淘宝网的开源架构(转)
  8. OSI[七层]与TCP/IP[四层]模型简述简图
  9. 给网站管理员的建议:创建可利用的、可抓取的网站
  10. 在ASP.NET中如何用C#.NET实现基于表单的验证