java线程之多个生产者消费者
2015-12-18 16:13
585 查看
温故一下上一节所学习的生产者消费者代码:
两个线程时:
通过标志位flag的if判断和同步函数互斥较好解决两个线程,一个生产者、一个消费者交替执行的功能
类名:ProducterConsumerDemo.java
代码:
ProducterConsumerDemo.java
如果再多加上两个线程呢?
即把其中的ProducterConsumerDemo类改为如下:
运行后发现,加上t3和t4之后结果就错了。
为什么两个线程的时候执行结果正确而四个线程的时候就不对了呢?
因为线程在wait()的时候,接收到其他线程的通知,即往下执行,不再进行判断。两个线程的情况下,唤醒的肯定是另一个线程;但是在多个线程的情况下,执行结果就会混乱无序。
比如,一个可能的情况是,一个增加线程执行的时候,其他三个线程都在wait,这时候第一个线程调用了notify()方法,其他线程都将被唤醒,然后执行各自的增加或减少方法。
解决的方法就是:在被唤醒之后仍然进行条件判断,去检查要改的数字是否满足条件,如果不满足条件就继续睡眠。
1)把两个方法中的if改为while即可。
2)需要将notify()改成notifyAll()
代码:
效果:
两个线程时:
通过标志位flag的if判断和同步函数互斥较好解决两个线程,一个生产者、一个消费者交替执行的功能
类名:ProducterConsumerDemo.java
代码:
class ProducterConsumerDemo { public static void main(String[] args) { Resources r =new Resources(); Productor pro =new Productor(r); Consumer con = new Consumer(r); Thread t1 =new Thread(pro); Thread t2 =new Thread(con); t1.start(); t2.start(); System.out.println("Hello World!"); } } class Resources { private String name; private int count =1; private boolean flag =false; public synchronized void set(String name) { if(flag) try{this.wait();}catch(Exception e){} this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"生产者"+this.name); flag =true; //唤醒对方进程 this.notify(); } public synchronized void out() { if(!flag) try{this.wait();}catch(Exception e){} System.out.println(Thread.currentThread().getName()+" ....消费者...."+this.name); flag =false; //唤醒对方进程 this.notify(); } } class Productor implements Runnable { private Resources res; Productor(Resources res){ this.res =res; } public void run(){ while(true){ res.set("++商品++"); } } } class Consumer implements Runnable { private Resources res; Consumer(Resources res){ this.res =res; } public void run(){ while(true){ res.out(); } } }
ProducterConsumerDemo.java
如果再多加上两个线程呢?
即把其中的ProducterConsumerDemo类改为如下:
class ProducterConsumerDemo2 { public static void main(String[] args) { Resources r =new Resources(); Productor pro =new Productor(r); Consumer con = new Consumer(r); Thread t1 =new Thread(pro); Thread t2 =new Thread(pro);//多个生产者 Thread t3 =new Thread(con); Thread t4 =new Thread(con);//多个消费者 t1.start(); t2.start(); t3.start(); t4.start(); System.out.println("Hello World!"); } }
运行后发现,加上t3和t4之后结果就错了。
为什么两个线程的时候执行结果正确而四个线程的时候就不对了呢?
因为线程在wait()的时候,接收到其他线程的通知,即往下执行,不再进行判断。两个线程的情况下,唤醒的肯定是另一个线程;但是在多个线程的情况下,执行结果就会混乱无序。
比如,一个可能的情况是,一个增加线程执行的时候,其他三个线程都在wait,这时候第一个线程调用了notify()方法,其他线程都将被唤醒,然后执行各自的增加或减少方法。
解决的方法就是:在被唤醒之后仍然进行条件判断,去检查要改的数字是否满足条件,如果不满足条件就继续睡眠。
1)把两个方法中的if改为while即可。
2)需要将notify()改成notifyAll()
代码:
/*
ProducterConsumerDemo解决了只有两个线程共享资源的生产消费问题,主要利用标志位的互斥解决
本程序致力于解决多出现多个生产者,多个消费者的时候,依然能够达到生产一次,消费一次的功能
:
解决的方法就是:1)在被唤醒之后仍然进行条件判断,去检查要改的数字是否满足条件,如果不满足条件就继续睡眠。把两个方法中的if改为while即可。
当然,此时仍会出现问题,就是所以线程都等待,失去资格
2)需要将notify()改成notifyAll()
*/
class ProducterConsumerDemo2 { public static void main(String[] args) { Resources r =new Resources(); Productor pro =new Productor(r); Consumer con = new Consumer(r); Thread t1 =new Thread(pro); Thread t2 =new Thread(pro);//多个生产者 Thread t3 =new Thread(con); Thread t4 =new Thread(con);//多个消费者 t1.start(); t2.start(); t3.start(); t4.start(); System.out.println("Hello World!"); } }
class Resources
{
private String name;
private int count =1;
private boolean flag =false;
public synchronized void set(String name)
{ //1)循环判断
while(flag)
try{this.wait();}catch(Exception e){}
this.name = name+"--"+count++;
System.out.println(Thread.currentThread().getName()+"生产者"+this.name);
flag =true;
//2)唤醒所有进程
this.notifyAll();
}
public synchronized void out()
{
//1)循环判断
while(!flag)
try{this.wait();}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+" ....消费者...."+this.name);
flag =false;
//2)唤醒所有进程
this.notifyAll();
}
}
class Productor implements Runnable
{
private Resources res;
Productor(Resources res){
this.res =res;
}
public void run(){
while(true){
res.set("++商品++");
}
}
}
class Consumer implements Runnable
{
private Resources res;
Consumer(Resources res){
this.res =res;
}
public void run(){
while(true){
res.out();
}
}
}
效果:
![](http://images2015.cnblogs.com/blog/756212/201512/756212-20151218161220396-1305884115.png)
相关文章推荐
- Mybatis3源码分析(06)-加载Configuration-缓存配置加载
- Struts问题: IllegalArgumentException occurred while calling setter of com.zzuli.
- eclipse删除svn下载的文件后如何恢复
- nested exception is javax.validation.ValidationException错误解决思路
- java设计模式之工厂模式
- Eclipse快捷键 10个最有用的快捷键
- 学了Java 你未必知道这些
- Java:按值传递还是按引用传递详细解说
- 使用axis创建调用 wsdl 形式的 webservice的方法
- javaEE缓存error保存
- java web 基础
- java对象的强引用,软引用,弱引用和虚引用
- MyEclipse中.classpath、.project、.mymetadata解读
- 关于Java图形化连接微软SQL server(含2005,2008,2012等)数据库的问题
- java的反射。
- Debian上安装java
- struts2 配置json格式数据( includeProperties中对list集合的正则配置)
- 10个Eclipse调试技巧
- 【转载】Eclipse 的快捷键以及文档注释、多行注释的快捷键
- Java标识符&关键字