生产者与消费者
一个生产者与一个消费者,要交替生产与消费。
package com.copy;
public class ProducerConsumerDemo {
public static void main(String[] args){
Resource res = new Resource();
Producer p = new Producer(res);
Consumer c = new Consumer(res);
Thread t1 = new Thread(p,"Thread1");
Thread t2 = new Thread(c,"Thread2");
t1.start();
t2.start();
}
}
class Resource{
private int n=1;
private boolean flag = false;//生没有生产好 true,生产者停
public synchronized void in(){
if(flag){
try{
wait();//写不写this都一样
}catch(InterruptedException e){
System.out.println("aaa");
}
}
try{Thread.sleep(5);}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"..生产.."+n);
flag = true;
this.notify();//写不写this都一样
}
public synchronized void out(){
if(!flag){
try{
wait();
}catch(InterruptedException e){
System.out.println("bbb");
}
}
try{Thread.sleep(5);}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"...消费..."+n);
n++;
flag = false;
notify();
}
}
class Producer implements Runnable{
private Resource res;
Producer(Resource res){
this.res=res;
}
public void run(){
//注意不能在这里synchronized,因为produer和consumer的对象不同。wait会报错。
while(true){
res.in();
}
}
}
class Consumer implements Runnable{
private Resource res;
Consumer(Resource res){
this.res=res;
}
public void run(){
while(true){
res.out();
}
}
}
如果有2个或者两个以上的消费者与生产者,如何交替生产与消费。
Thread t1 = new Thread(p,"Thread1"); Thread t1 = new Thread(p,"Thread2"); Thread t3 = new Thread(c,"Thread3"); Thread t4 = new Thread(c,"Thread4"); t1.start(); t2.start(); t3.start(); t4.start();
但是这样发现了问题,会重复生产或者重复消费。
t1获得执行资格,判断if,打印“生产90”,置flag为true。
t1获得执行资格,判断if,wait了。
t2获得执行资格,判断if,wait了。
t3获得执行资格,判断if,打印“消费90”,n变为91,置flag为false,notify了t1。
t1获得执行资格,接着wait的地方继续运行(不需要判断flag了),打印“生产91”,置flag为true,notify了t2.
t2获得执行资格,接着wait的地方继续运行,这时flag为true对它已经没用了,不需要判断了,打印“生产91”,notify(其实现在也没线程在等)。
所以出现了错误的结果。
因此要把两个if改为while,让线程每次被唤醒的时候都去判断flag。(这时候不要觉得会一直循环判断停不下来。为true,wait;为false,循环结束)
但这时运行,发现程序可能一直停着不动了。
t1获得执行资格,判断if,打印“生产1”,置flag为true。
t1获得执行资格,判断if,wait。
t2获得执行资格,判断if,wait。
t3获得执行资格,判断if,打印“消费1”,n变为2,置flag为true,notify了t1。
t4获得执行资格,判断if,wait。
t1获得执行资格,判断if,打印“生产2”,置flag为true,notify了t2。
t2获得执行资格,判断if,wait了。
t1获得执行资格,判断if,wait了。
现在只有t3不在wait。
t3获得执行资格,判断if,打印“消费2”,n变为3,置flag为false,notify了t4。
t3/t4判断,都wait了。现在t1/t2也在wait,所以程序停着不动了。
也就是说notify唤醒了本方(生产者或是消费者),在对方都wait的情况下一个都没唤醒,所以一直等待。(唤醒的本方while判断还是会wait,所以都wait了)
所以还要把两个notify改为notifyAll。
多生产者,消费者的情况,用while和notifyAll。
这种方法还可以改进。(JDK5.0)
java.util.concurrent.locks类中有Lock和Condition两个接口,ReentrantLock类(实现了Lock接口)。
Lock的锁定操作比synchronized更灵活,可以支持多个Condition对象。
Lock的方法,lock()与unlock(),显式地加/释放锁。
Condition的方法,await()(throws InterruptedException),signal(),signalAll()分别替代了wait()(throws InterruptedException),notify(),notifyAll()这三种Object类的方法。
当拿到锁执行代码时,发生了异常,程序结束,但锁还没有释放,因此unlock操作要放到finally里。
改进后的代码
class Resource{
private int n=1;
private boolean flag = false;
private Lock lock = new ReentrantLock();
private Condition condition_pro = lock.newCondition();
private Condition condition_con = lock.newCondition();
public void in() throws InterruptedException{
lock.lock();
try{
while(flag){
condition_pro.await();
}
System.out.println(Thread.currentThread().getName()+"..生产.."+n);
flag = true;
condition_con.signal();//只唤醒对方
}finally{
lock.unlock();
}
}
public void out()throws InterruptedException{
lock.lock();
try{
while(!flag){
condition_con.await();
}
System.out.println(Thread.currentThread().getName()+"...消费..."+n);
n++;
flag = false;
condition_pro.signal();//只唤醒对方
}finally{
lock.unlock();
}
}
}
class Producer implements Runnable{
private Resource res;
Producer(Resource res){
this.res=res;
}
public void run(){
while(true){
try{//throws之后,这里要处理
res.in();
}catch(InterruptedException e){
}
}
}
}
class Consumer implements Runnable{
private Resource res;
Consumer(Resource res){
this.res=res;
}
public void run(){
while(true){
try{//throws之后,这里要处理
res.out();
}catch(InterruptedException e){
}
}
}
}
前面synchronized的wait和notifyAll(如果没有synchronized,notify会IllegalMonitorStateException,毕竟有锁才会有唤醒等待机制)唤醒了对方和本方的所有等待线程,这样不好,只要唤醒对方的就好了。这是condition的好处。

浙公网安备 33010602011771号