线程安全-生产者消费者demo
* 生产消费线程同步演示
* 同步方式:使用synchronized代码块作为同步机制实现同步与互斥,用等待唤醒作为线程通信方式,
* 使用库存len作为线程共享(同步)变量
* 生产和消防线程本身并不相关,商品仓库才是他们的共享资源(临界区), 使用生产消费的同步关键就是对仓库数据操作的同步,同一时间只允许一个线程进入.
* 注意事项:
* 信号量或同步参数的设置 (至关重要)。设置不当会同步失败,或死锁
* 调用并进入临界区操作后,离开时一定要释放资源并唤醒其他线程(notify 或 V操作)
* 相当于调用完同步代码后一定要调用notify唤醒操作,当有多个线程是要使用 notifyAll
* 临界区的共享变量,每一次进入都需要重新检查.
示例代码:
1 public class Demo { 2 3 /** 4 * @param args 5 */ 6 public static void main(String[] args) { 7 // TODO Auto-generated method stub 8 new Thread(new Production()).start(); 9 new Thread(new Consumption()).start(); 10 11 } 12 13 } 14 //Production consumption warehouse 15 // 16 /** 17 * 18 * @ClassName: Warehouse 19 * @Description: TODO 仓库 20 * @author: zw 21 * @date: 2018年3月27日 下午1:26:49 22 */ 23 class Warehouse{ 24 //库存数量,也用来指示 array下标 25 private int len = -1; //共享变量 26 //仓库 27 private int[] array = new int[10]; //共享变量 28 29 private static Warehouse wh = new Warehouse(); 30 31 //单例, 一个仓库 32 private Warehouse(){} 33 public static Warehouse getWarehouse(){ 34 return wh; 35 } 36 37 38 /** 39 * 40 * @Title: out 41 * @Description: TODO 出仓<br> 如果没有库存就叫醒(notify)生产线程制造商品,然后wait.如果有库存,就拿走一件并且库存减1 42 * @param @return 43 * @param @throws InterruptedException 44 * @return int 仓库里的商品编号 45 * @throws 46 */ 47 public int out() throws InterruptedException { 48 synchronized(this){ 49 while(this.len < 0){ 50 //没有库存 51 this.notify(); 52 this.wait(); 53 } 54 55 return array[len--]; 56 57 } 58 } 59 60 // 61 /** 62 * @Title: in 63 * @Description: TODO 商品入仓<br> len < array.length-1 就表示仓库未满,则入仓并唤醒 消费者 ,如果仓库满就 wait 64 * @param @param len 商品编号 65 * @param @throws InterruptedException 设定文件 66 * @return void 返回类型 67 * @throws 68 */ 69 public void in(int pid) throws InterruptedException { 70 synchronized(this){ 71 while(this.len >= array.length-1){ 72 this.wait(); 73 } 74 array[++len] = pid; 75 this.notify(); 76 } 77 78 } 79 80 81 } 82 83 /** 84 * 85 * @ClassName: Production 86 * @Description: TODO 生产者 87 * @author: zw 88 * @date: 2018年3月27日 下午12:10:50 89 */ 90 class Production implements Runnable{ 91 Warehouse arr = Warehouse.getWarehouse(); 92 public void run(){ 93 for(int i = 0; i < 100; i++){ 94 try { 95 //第i号产品入仓 96 arr.in(i); 97 } catch (InterruptedException e) { 98 // TODO Auto-generated catch block 99 e.printStackTrace(); 100 } 101 System.out.println("made:....."+i); 102 } 103 } 104 } 105 106 107 /** 108 * 109 * @ClassName: Consumption 110 * @Description: TODO 消费者 111 * @author: zw 112 * @date: 2018年3月27日 下午12:12:18 113 */ 114 class Consumption implements Runnable{ 115 Warehouse arr = Warehouse.getWarehouse(); 116 117 public void run(){ 118 int pid = -1; 119 for(int i = 0; i < 100; i++){ 120 try { 121 pid = arr.out(); 122 } catch (InterruptedException e) { 123 // TODO Auto-generated catch block 124 e.printStackTrace(); 125 } 126 System.out.println(i+"consumption:--"+pid); 127 128 } 129 } 130 }