您的位置:首页 > 编程语言 > Java开发

java线程之多个生产者消费者2.0

2015-12-18 17:46 459 查看
上一节中,通过while和notifyAll解决了多个生产者,消费者对共享资源的访问问题,现在开始升级

但是,仍然有改进之处,主要体现在两点:

1)使用新版本1.5开始后的锁Lock解决,目的将其全部替换实现相同功能

2)由于notifyAll唤醒的是己方和对方线程,我们优化的是只唤醒对方进程

方案1,使用while和notifyAll,synchronized解决多线程访问

代码:

/*
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();
}
}

}


ProducterConsumerDemo2.java
方案2,解决改进1)的问题

升级版:
使用Lock来替换synchronized,wait,notify,nonifyAll语法和语句的使用
不需要同步,不需要notify

记得需要导包:

java.util.concurrent.locks

主要改动:

自定义锁 ---》 Condition对象 --》signallAll

condition.await() === try{this.wait();}catch(Exception e){}

synchronized删除,异常抛出,使用finally解锁

/*

本程序致力于解决多出现多个生产者,多个消费者的时候,依然能够达到生产一次,消费一次的功能
:
解决的方法就是:1)在被唤醒之后仍然进行条件判断,去检查要改的数字是否满足条件,如果不满足条件就继续睡眠。把两个方法中的if改为while即可。
当然,此时仍会出现问题,就是所以线程都等待,失去资格
2)需要将notify()改成notifyAll()

升级版:
使用Lock来替换synchronized,wait,notify,nonifyAll语法和语句的使用
不需要同步,不需要notify
*/
import java.util.concurrent.locks.*;
class  ProducterConsumerDemo3
{
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;
private Lock lock = new ReentrantLock();

private Condition condition = lock.newCondition();

public  void set(String name) throws InterruptedException
{
lock.lock();
try
{
//1)循环判断
while(flag)
//如果为真,放弃资格
condition.await(); //会抛出异常
this.name = name+"--"+count++;

System.out.println(Thread.currentThread().getName()+"生产者"+this.name);
flag =true;
//2)使用condition唤醒所有进程
condition.signalAll(); //如果使用condition.signal()会出现相互等待状况,都失去资格
}
finally
{
lock.unlock();
}

}
public  void out() throws InterruptedException
{
lock.lock();
try
{
//1)循环判断
while(!flag)
condition.await();

System.out.println(Thread.currentThread().getName()+" ....消费者...."+this.name);
flag =false;
//2)使用condition唤醒所有进程
condition.signalAll();
}
finally    //防止当前线程拿到锁后抛异常一直不释放锁
{
lock.unlock();
}

}
}

class Productor implements Runnable
{
private Resources res;
Productor(Resources res){
this.res =res;
}
public void run(){
while(true){
try
{
res.set("++商品++"); //需要抛出异常
}
catch (InterruptedException e)
{
}

}
}

}

class Consumer  implements Runnable
{
private Resources res;
Consumer(Resources res){
this.res =res;
}
public void run(){
while(true){
try
{
res.out(); //需要抛出异常
}
catch (InterruptedException e)
{
}

}
}

}


此时实现功能和方案1功能一样

方案3,在方案2的基础上解决改进2)的问题

加强升级版:

此版本为最终版,主要在使用锁lock的基础上,加上唤醒对方(不包括己方)进程的优化

/*

本程序致力于解决多出现多个生产者,多个消费者的时候,依然能够达到生产一次,消费一次的功能
:
解决的方法就是:1)在被唤醒之后仍然进行条件判断,去检查要改的数字是否满足条件,如果不满足条件就继续睡眠。把两个方法中的if改为while即可。
当然,此时仍会出现问题,就是所以线程都等待,失去资格
2)需要将notify()改成notifyAll()

升级版:
使用Lock来替换synchronized,wait,notify,nonifyAll语法和语句的使用
不需要同步,不需要notify
------------
加强升级版:
此版本为最终版,主要在使用锁lock的基础上,加上唤醒对方(不包括己方)进程的优化
通过一个锁建立多个condition对象来解决

流程:
生产者拿到锁,执行,判断没有真,继续执行,生产完毕后唤醒消费者来消费    生产者唤醒消费者
 消费者拿到锁,执行,判断没有假,继续执行,消费完毕后唤醒生产者继续生产   消费者唤醒生产者

*/
import java.util.concurrent.locks.*;
class  ProducterConsumerDemo4
{
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;
private Lock lock = new ReentrantLock();

private Condition condition_pro = lock.newCondition(); //使用lock建立生产者的condition对象
private Condition condition_con = lock.newCondition(); //使用lock建立消费者的condition对象

public  void set(String name) throws InterruptedException
{
lock.lock();
try
{
//1)循环判断
while(flag)
//如果为真,放弃生产者的资格
condition_pro.await(); //会抛出异常
this.name = name+"--"+count++;

System.out.println(Thread.currentThread().getName()+"生产者"+this.name);
flag =true;
//2)使用消费condition唤醒进程
condition_con.signal(); //生产者生产完毕后,唤醒消费者的进程(不再是signalAll)
}
finally
{
lock.unlock();
}

}
public  void out() throws InterruptedException
{
lock.lock();
try
{
//1)循环判断
while(!flag)
//如果为假,放弃消费者的资格
condition_con.await();

System.out.println(Thread.currentThread().getName()+" ....消费者...."+this.name);
flag =false;
//2)使用生产者condition唤醒进程
condition_pro.signal(); //消费者消费完毕后,唤醒生产者的进程
}
finally    //防止当前线程拿到锁后抛异常一直不释放锁
{
lock.unlock();
}

}
}

class Productor implements Runnable
{
private Resources res;
Productor(Resources res){
this.res =res;
}
public void run(){
while(true){
try
{
res.set("++商品++"); //需要抛出异常
}
catch (InterruptedException e)
{
}

}
}

}

class Consumer  implements Runnable
{
private Resources res;
Consumer(Resources res){
this.res =res;
}
public void run(){
while(true){
try
{
res.out(); //需要抛出异常
}
catch (InterruptedException e)
{
}

}
}

}


图示:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: