线程学习三:生产者/消费者模式

原理:

  生产者/消费者模式就是将生产和消费分成多个线程,他们并用一个仓库。当仓库满的时候不能再生产,只能等消费了以后才能继续生产;当仓库空的时候不能再消费,必须等到生产了之后才能消费。

  这个实现的手段有三种:使用wait() / notify()方法;使用await() / signal()方法;使用BlockingQueue阻塞队列方法

实现:

  一、使用wait() / notify()方法

  wait() / nofity()方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制。

  wait()方法:当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等等状态,让其他线程执行。

  notify()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。

 1 public class ProConTest {
 2     public final int MAX_SIZE = 10;
 3     public LinkedList<Object> list = new LinkedList<Object>();
 4 
 5     public static void main(String[] args) {
 6         ProConTest pct = new ProConTest();
 7         Producer producer = pct.new Producer();
 8         Consumer consumer = pct.new Consumer();
 9         producer.start();
10         consumer.start();
11     }
12 
13     class Producer extends Thread {
14 
15         @Override
16         public void run() {
17             Producer();
18         }
19 
20         public void Producer() {
21             while (true) {
22                 synchronized (list) {
23                     if (list.size() == MAX_SIZE) {
24                         System.out.println("已经满仓,不能再生产了");
25                         try {
26                             list.wait();
27                         } catch (InterruptedException e) {
28                             e.printStackTrace();
29                         }
30                     }
31                     list.add(1);
32                     System.out.println("现在仓库剩余" + list.size());
33                     list.notifyAll();
34                 }
35             }
36         }
37     }
38 
39     class Consumer extends Thread {
40 
41         @Override
42         public void run() {
43             Consumer();
44         }
45 
46         public void Consumer() {
47             while (true) {
48                 synchronized (list) {
49                     if (list.size() == 0) {
50                         System.out.println("仓库已经卖完,不能再消费了");
51                         try {
52                             list.wait();
53                         } catch (InterruptedException e) {
54                             e.printStackTrace();
55                         }
56                     }
57                     list.remove();
58                     System.out.println("现在仓库剩余" + list.size());
59                     list.notifyAll();
60                 }
61             }
62         }
63     }
64 
65 }

  二、使用await() / signal()方法

  在JDK5.0之后,Java提供了更加健壮的线程处理机制,包括同步、锁定、线程池等,它们可以实现更细粒度的线程控制。await()和signal()就是其中用来做同步的两种方法,它们的功能基本上和wait() / nofity()相同,完全可以取代它们,但是它们和新引入的锁定机制Lock直接挂钩,具有更大的灵活性。通过在Lock对象上调用newCondition()方法,将条件变量和一个锁对象进行绑定,进而控制并发程序访问竞争资源的安全。

 1 public class ProConTest2 {
 2     public final int MAX_SIZE = 10;
 3     public LinkedList<Object> list = new LinkedList<Object>();
 4     private final Lock lock = new ReentrantLock();
 5     private final Condition full = lock.newCondition();
 6     private final Condition empty = lock.newCondition();
 7 
 8     public static void main(String[] args) {
 9         ProConTest2 pct = new ProConTest2();
10         Producer producer = pct.new Producer();
11         Consumer consumer = pct.new Consumer();
12         producer.start();
13         consumer.start();
14     }
15 
16     class Producer extends Thread {
17 
18         @Override
19         public void run() {
20             Producer();
21         }
22 
23         public void Producer() {
24             while (true) {
25                 lock.lock();
26                 if (list.size() == MAX_SIZE) {
27                     System.out.println("已经满仓,不能再生产了");
28                     try {
29                         full.await();
30                     } catch (InterruptedException e) {
31                         e.printStackTrace();
32                     }
33                 }
34                 list.add(1);
35                 System.out.println("现在仓库剩余" + list.size());
36                 full.signalAll();
37                 empty.signalAll();
38                 lock.unlock();
39 
40             }
41         }
42     }
43 
44     class Consumer extends Thread {
45 
46         @Override
47         public void run() {
48             Consumer();
49         }
50 
51         public void Consumer() {
52             while (true) {
53                 lock.lock();
54                 if (list.size() == 0) {
55                     System.out.println("仓库已经卖完,不能再消费了");
56                     try {
57                         empty.await();
58                     } catch (InterruptedException e) {
59                         e.printStackTrace();
60                     }
61                 }
62                 list.remove();
63                 System.out.println("现在仓库剩余" + list.size());
64                 full.signalAll();
65                 empty.signalAll();
66                 lock.unlock();
67 
68             }
69         }
70     }
71 }

  三、使用BlockingQueue阻塞队列方法

  BlockingQueue是JDK5.0的新增内容,它是一个已经在内部实现了同步的队列,实现方式采用的是我们第2种await() / signal()方法。它可以在生成对象时指定容量大小。它用于阻塞操作的是put()和take()方法。

  put()方法:类似于我们上面的生产者线程,容量达到最大时,自动阻塞。

  take()方法:类似于我们上面的消费者线程,容量为0时,自动阻塞。

 1 public class ProConTest3 {
 2     public final int MAX_SIZE = 10;
 3     private LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>(MAX_SIZE);
 4 
 5     public static void main(String[] args) {
 6         ProConTest3 pct = new ProConTest3();
 7         Producer producer = pct.new Producer();
 8         Consumer consumer = pct.new Consumer();
 9         producer.start();
10         consumer.start();
11     }
12 
13     class Producer extends Thread {
14 
15         @Override
16         public void run() {
17             Producer();
18         }
19 
20         public void Producer() {
21             while (true) {
22                 if (queue.size() == MAX_SIZE) {
23                     System.out.println("已经满仓,不能再生产了");
24                 }
25                 try {
26                     queue.put(1);
27                 } catch (InterruptedException e) {
28                     e.printStackTrace();
29                 }
30                 System.out.println("现在仓库剩余" + queue.size());
31             }
32         }
33     }
34 
35     class Consumer extends Thread {
36 
37         @Override
38         public void run() {
39             Consumer();
40         }
41 
42         public void Consumer() {
43             while (true) {                
44                 if (queue.size() == 0) {
45                     System.out.println("仓库已经卖完,不能再消费了");
46                 }
47                 try {
48                     queue.take();
49                 } catch (InterruptedException e) {
50                     e.printStackTrace();
51                 }
52                 System.out.println("现在仓库剩余" + queue.size());
53             }
54         }
55     }
56 
57 }

 

参考

JAVA编程思想

http://blog.csdn.net/monkey_d_meng/article/details/6251879

 

posted @ 2016-09-22 17:01  夜晚风吻尽  阅读(230)  评论(0编辑  收藏  举报