java学习之多生产者和多消费者

在上一节当中我们说道了,java多线程当中单个消费者对应单个生产者的关系。这个时候有几个点需要注意一下,第一个就是把if判断flag的语句改成while这样能够避免,比如如果我们这个时候用if的话判断完为真之后,线程就睡过去了,但是当下一次线程notify的时候,这个时候生产者还有消费者,也就是一个锁上面的线程拥有线程苏醒的机会是等同的。这个时候,如果生产者冻结之后,紧接着notify的话这个时候苏醒的还可能是生产者,这是我们不愿意看到的。那我们应该如何来处理呢,这个时候我们就应该把if改成while因为while是个循环,当下一次该线程苏醒的时候还应到回过头来判断,flag标记,这样就避免了生产者自我唤醒的这种情况。

但是现在问题变了,就是这个时候有多个生产者还有多个消费者,我们知道当只有一个生产者还有一个消费者的时候,至少会唤醒其中的一个,那么要是多个生产者还有多个消费者呢,我们可以这样想一下,比如说这个时候有两个生产者A和B,还有两个消费者C和D,此时A生产完了之后,这个时候A就开始唤醒了,假如A唤醒了C这个时候C开始生产消费产品,消费完了之后开始通知其他线程,这个时候假如被唤醒的是D线程,因为flag是假的证明已经没有东西可消费了,这个时候他又冻结。那么这个时候其他线程就都被冻结了,这个时候就形成了死锁现象,如果要避免死锁现象的话,java又为我们提供了一个方法,叫做notifyAll()方法,这个方法的作用在于能够把所有的线程都唤醒,这样就能保证消费者还有生产者至少可以唤醒双方的一个线程,保证程序的正常运行。这样做的一个缺点就是其中还有一个属于己方的线程被唤醒,这样就浪费了资源。于是在jdk更新的时候,就为我们提供了一个新的api能够显式的来操作锁还有唤醒冻结线程,这个线程不再核心lang包当中,这个apijava.util.concurrent.locks这个包当中为我们提供了两个接口,一是Lock接口还有一个是Condition接口。Lock接口扩展的方法有lock()方法还有一个unlock方法,这里需要注意的一点是,无论如何一定要释放锁,这个时候就用到了前面异常所讲到的finally语句,无论如何一定要执行。Lock当中还扩展了一个方法就是newCondition()这个方法,这个方法的作用是给一个锁定义多个消息传递的方式也就是给线程绑定多个监视器,比如说生产者只唤醒消费者的线程,而不唤醒生产者的线程,同理消费者也是如此。同时在Lock当中等待的方法不是wait()方法,唤醒的方法也不是notify()方法,这两个方法分别对应Lock当中的await()方法和signal()方法。

我们综合上面所讲来用代码体现下:

  1 import java.util.concurrent.locks.*;
  2 class KaoYa
  3 {
  4 
  5     int num = 1;
  6 
  7     Lock l = new ReentrantLock();
  8 
  9     Condition c1 = l.newCondition(); 
 10     Condition c2 = l.newCondition(); 
 11 
 12     boolean flag;
 13 
 14     public void produce() throws InterruptedException
 15     {
 16             l.lock();
 17             
 18             try{
 19                 while(true)
 20                 {
 21                     while(flag)
 22                         c1.await();
 23                         System.out.println(Thread.currentThread().getName()+"KaoYa...."+num);
 24                         flag = true;
 25                         c2.signal();
 26                 }        //num++;
 27         
 28             }finally
 29             {
 30                 l.unlock();
 31             }
 32     }
 33 
 34     public void consume() throws InterruptedException
 35     {
 36         l.lock();
 37             
 38             try{
 39                 while(true)
 40                 {
 41                     while(!flag)
 42                         c2.await();
 43                     System.out.println(Thread.currentThread().getName()+"KaoYa------"+num);
 44                     num++;
 45                     flag = false;
 46                     c1.signal();    
 47                 }                
 48             }finally
 49             {
 50 
 51                 l.unlock();
 52 
 53             }
 54     }
 55 
 56 }
 57 
 58 class Product implements Runnable
 59 {
 60 
 61     KaoYa k;
 62     Product(KaoYa k)
 63     {
 64 
 65         this.k = k;
 66 
 67     }
 68 
 69     public void run()
 70     {
 71         try{
 72             k.produce();
 73         }catch(InterruptedException e)
 74         {
 75 
 76         }
 77     }
 78 }
 79 
 80 
 81 class Consume implements Runnable
 82 {
 83 
 84     KaoYa k;
 85     Consume(KaoYa k)
 86     {
 87 
 88         this.k = k;
 89 
 90     }
 91 
 92     public void run()
 93     {
 94     
 95         try{
 96             k.consume();
 97         }catch(InterruptedException e)
 98         {
 99 
100         }
101             
102 
103     }
104 
105 
106 }
107 
108 class LockDemo
109 {
110 
111     public static void main(String[] args) {
112         
113         KaoYa k = new KaoYa();
114         Product p = new Product(k);
115         Consume c = new Consume(k);
116 
117         Thread t1 = new Thread(p);
118         Thread t2 = new Thread(p);
119         Thread t3 = new Thread(c);
120         Thread t4 = new Thread(c);
121 
122 
123         t1.start();
124         t2.start();
125         t3.start();
126         t4.start();
127 
128     }
129 
130 }

原文地址:https://www.cnblogs.com/sunchuanzhen/p/3381459.html