有前面的基础我们基本上就可以实现一个经典的生产者消费者模式了,下面直接贴出代码:
1 package com.fanjf.thread; 2 3 import java.util.LinkedList; 4 import java.util.Random; 5 public class Mycontainer4 { 6 LinkedList<String> list = new LinkedList<String>(); 7 final int MAX = 100; 8 private synchronized void put(String s){ 9 while(list.size()==MAX){ 10 try { 11 this.wait(); 12 } catch (InterruptedException e) { 13 e.printStackTrace(); 14 } 15 } 16 list.add(s); 17 this.notifyAll(); 18 } 19 20 private synchronized String get(){ 21 String s = null; 22 while(list.size()==0){ 23 try { 24 this.wait(); 25 } catch (InterruptedException e) { 26 e.printStackTrace(); 27 } 28 } 29 s = list.removeFirst(); 30 this.notifyAll(); 31 return s; 32 33 } 34 public static void main(String[] args) { 35 final Mycontainer4 mycontainer4 = new Mycontainer4(); 36 //启动消费者线程 37 for(int i = 0;i<10;i++){ 38 new Thread(new Runnable() { 39 public void run() { 40 for(int j = 0;j<10;j++){ 41 System.out.println("消费者线程"+Thread.currentThread().getName()+"取出:"+mycontainer4.get()); 42 } 43 44 } 45 },"c"+i).start(); 46 } 47 //启动生产者线程 48 for(int i = 0;i<10;i++){ 49 new Thread(new Runnable() { 50 public void run() { 51 for(int j = 0;j<10;j++){ 52 Random random = new Random(); 53 int r = random.nextInt(10); 54 System.out.println("生产者者线程"+Thread.currentThread().getName()+"放入:"+r); 55 mycontainer4.put(Integer.toString(r)); 56 } 57 58 } 59 },"p"+i).start(); 60 } 61 62 } 63 }
执行结果如下:
1 生产者者线程p3放入:8 2 生产者者线程p1放入:3 3 生产者者线程p0放入:7 4 生产者者线程p6放入:6 5 生产者者线程p3放入:8 6 生产者者线程p6放入:9 7 生产者者线程p2放入:7 8 消费者线程c9取出:8 9 消费者线程c8取出:7 10 消费者线程c7取出:6 11 生产者者线程p6放入:4 12 生产者者线程p8放入:9 13 生产者者线程p3放入:3 14 生产者者线程p4放入:0 15 生产者者线程p5放入:8 16 生产者者线程p0放入:5 17 生产者者线程p5放入:2 18 消费者线程c3取出:8 19 生产者者线程p4放入:9 20 消费者线程c9取出:0 21 消费者线程c8取出:3 22 生产者者线程p3放入:0 23 生产者者线程p8放入:0 24 消费者线程c1取出:9 25 消费者线程c1取出:0 26 生产者者线程p6放入:6 27 消费者线程c7取出:4 28 生产者者线程p9放入:6 29 生产者者线程p1放入:6 30 消费者线程c0取出:3 31 消费者线程c5取出:9 32 消费者线程c4取出:7 33 生产者者线程p7放入:7 34 消费者线程c6取出:8 35 生产者者线程p2放入:0 36 消费者线程c6取出:7 37 生产者者线程p7放入:2 38 生产者者线程p7放入:9 39 消费者线程c0取出:6 40 生产者者线程p1放入:0 41 生产者者线程p9放入:5 42 消费者线程c7取出:6 43 消费者线程c1取出:6 44 生产者者线程p6放入:4 45 生产者者线程p8放入:0 46 生产者者线程p3放入:3 47 消费者线程c8取出:0 48 消费者线程c9取出:9 49 生产者者线程p4放入:1 50 消费者线程c3取出:2 51 消费者线程c3取出:1 52 生产者者线程p5放入:4 53 生产者者线程p0放入:7 54 消费者线程c2取出:5 55 生产者者线程p0放入:9 56 生产者者线程p5放入:3 57 消费者线程c3取出:4 58 生产者者线程p4放入:0 59 消费者线程c9取出:3 60 消费者线程c8取出:0 61 生产者者线程p3放入:5 62 生产者者线程p8放入:3 63 生产者者线程p6放入:7 64 消费者线程c1取出:4 65 消费者线程c7取出:5 66 生产者者线程p9放入:2 67 生产者者线程p1放入:0 68 消费者线程c0取出:0 69 生产者者线程p7放入:0 70 消费者线程c4取出:9 71 消费者线程c6取出:2 72 生产者者线程p2放入:3 73 消费者线程c5取出:0 74 消费者线程c5取出:0 75 消费者线程c5取出:3 76 生产者者线程p2放入:0 77 消费者线程c6取出:0 78 消费者线程c4取出:2 79 生产者者线程p7放入:7 80 生产者者线程p7放入:2 81 消费者线程c4取出:7 82 消费者线程c0取出:7 83 生产者者线程p1放入:6 84 生产者者线程p9放入:4 85 消费者线程c7取出:3 86 消费者线程c1取出:5 87 生产者者线程p6放入:8 88 生产者者线程p8放入:6 89 生产者者线程p3放入:3 90 消费者线程c8取出:0 91 消费者线程c9取出:3 92 生产者者线程p4放入:6 93 消费者线程c3取出:9 94 生产者者线程p5放入:8 95 生产者者线程p0放入:7 96 消费者线程c2取出:7 97 生产者者线程p0放入:2 98 消费者线程c3取出:8 99 生产者者线程p5放入:1 100 生产者者线程p4放入:5 101 消费者线程c9取出:6 102 消费者线程c8取出:3 103 生产者者线程p3放入:7 104 生产者者线程p8放入:3 105 消费者线程c7取出:6 106 消费者线程c1取出:8 107 生产者者线程p6放入:4 108 生产者者线程p9放入:6 109 消费者线程c4取出:4 110 消费者线程c4取出:4 111 消费者线程c4取出:6 112 生产者者线程p1放入:4 113 消费者线程c0取出:6 114 消费者线程c6取出:2 115 生产者者线程p7放入:0 116 消费者线程c5取出:0 117 生产者者线程p2放入:3 118 消费者线程c6取出:0 119 生产者者线程p7放入:8 120 生产者者线程p1放入:1 121 消费者线程c4取出:4 122 生产者者线程p9放入:3 123 生产者者线程p6放入:0 124 消费者线程c1取出:3 125 消费者线程c7取出:7 126 生产者者线程p8放入:9 127 生产者者线程p3放入:0 128 消费者线程c8取出:5 129 消费者线程c9取出:1 130 生产者者线程p4放入:9 131 生产者者线程p5放入:5 132 消费者线程c3取出:2 133 生产者者线程p0放入:4 134 消费者线程c2取出:7 135 生产者者线程p0放入:3 136 消费者线程c3取出:5 137 消费者线程c3取出:3 138 生产者者线程p5放入:7 139 消费者线程c9取出:9 140 生产者者线程p4放入:6 141 消费者线程c8取出:0 142 生产者者线程p3放入:6 143 消费者线程c8取出:6 144 生产者者线程p8放入:1 145 消费者线程c7取出:9 146 消费者线程c1取出:0 147 生产者者线程p6放入:7 148 消费者线程c4取出:3 149 生产者者线程p9放入:3 150 生产者者线程p1放入:9 151 消费者线程c0取出:1 152 消费者线程c6取出:8 153 生产者者线程p7放入:1 154 消费者线程c5取出:3 155 生产者者线程p2放入:8 156 消费者线程c6取出:1 157 生产者者线程p7放入:3 158 消费者线程c6取出:3 159 生产者者线程p1放入:6 160 消费者线程c7取出:9 161 生产者者线程p9放入:4 162 消费者线程c4取出:3 163 消费者线程c1取出:7 164 生产者者线程p8放入:5 165 消费者线程c8取出:1 166 生产者者线程p4放入:8 167 消费者线程c9取出:6 168 消费者线程c3取出:7 169 生产者者线程p5放入:9 170 生产者者线程p0放入:2 171 消费者线程c9取出:9 172 消费者线程c2取出:4 173 生产者者线程p0放入:3 174 生产者者线程p5放入:4 175 生产者者线程p4放入:0 176 消费者线程c0取出:8 177 消费者线程c1取出:5 178 生产者者线程p8放入:7 179 消费者线程c7取出:4 180 生产者者线程p9放入:5 181 消费者线程c6取出:6 182 生产者者线程p1放入:8 183 生产者者线程p2放入:8 184 消费者线程c5取出:8 185 生产者者线程p2放入:6 186 生产者者线程p9放入:1 187 消费者线程c0取出:3 188 消费者线程c2取出:2 189 消费者线程c0取出:0 190 生产者者线程p2放入:3 191 消费者线程c5取出:4 192 生产者者线程p2放入:0 193 消费者线程c0取出:5 194 消费者线程c2取出:7 195 消费者线程c5取出:8 196 消费者线程c2取出:8 197 消费者线程c5取出:6 198 消费者线程c2取出:1 199 消费者线程c2取出:3 200 消费者线程c2取出:0
我们来解释一下上面的代码,首先我们创建了一个容器Mycontainer4,我们在容器中定义了一个MAX变量,一个list变量,这个容器中有一个同步方法put,一个同步方法get,put方法往list中增加元素,然后通知等待的线程消费,当list的size达到我们设定的阈值MAX时,调用此方法的线程阻塞。get方法从list中移除元素,然后通知生产者线程生产,当list的size等于0时,调用get方法的线程阻塞。在main方法中我们启动了十个生产者线程往list中各增加10个1到10之间的随机数,同时启动了十个消费者线程进行消费,这里我们主要注意的是get和put方法里判断list的size时我们必须使用while,而不能使用if,想一下为什么,比如此时我们的list为0,消费者线程将阻塞,此时其中一个生产者线程得到了锁,往list中add了十个元素,然后执行notifyAll唤醒等待的线程,此时正好其中的一个消费者线程获得了锁,然后立即remove了十个元素,让后notifyAll唤醒等待的线程,此时可能生产者并没有获得锁,而是另外一个消费者获得锁,如果用if,此时的这个消费者并不会再一次判断list的size,而是直接从wait后开始执行,而此时size为0,remove时就会报NoSuchElementException异常,如果改用while的话,就会再重新检查下list的size,所以这里我们必须要用while来保证循环检查。