上一节中,通过while和notifyAll解决了多个生产者,消费者对共享资源的访问问题,现在开始升级
但是,仍然有改进之处,主要体现在两点:
1)使用新版本1.5开始后的锁Lock解决,目的将其全部替换实现相同功能
2)由于notifyAll唤醒的是己方和对方线程,我们优化的是只唤醒对方进程
方案1,使用while和notifyAll,synchronized解决多线程访问
代码:
/* ProducterConsumerDemo解决了只有两个线程共享资源的生产消费问题,主要利用标志位的互斥解决 本程序致力于解决多出现多个生产者,多个消费者的时候,依然能够达到生产一次,消费一次的功能 : 解决的方法就是:1)在被唤醒之后仍然进行条件判断,去检查要改的数字是否满足条件,如果不满足条件就继续睡眠。把两个方法中的if改为while即可。 当然,此时仍会出现问题,就是所以线程都等待,失去资格 2)需要将notify()改成notifyAll() */ class ProducterConsumerDemo2 { public static void main(String[] args) { Resources r =new Resources(); Productor pro =new Productor(r); Consumer con = new Consumer(r); Thread t1 =new Thread(pro); Thread t2 =new Thread(pro);//多个生产者 Thread t3 =new Thread(con); Thread t4 =new Thread(con);//多个消费者 t1.start(); t2.start(); t3.start(); t4.start(); System.out.println("Hello World!"); } } class Resources { private String name; private int count =1; private boolean flag =false; public synchronized void set(String name) { //1)循环判断 while(flag) try{this.wait();}catch(Exception e){} this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"生产者"+this.name); flag =true; //2)唤醒所有进程 this.notifyAll(); } public synchronized void out() { //1)循环判断 while(!flag) try{this.wait();}catch(Exception e){} System.out.println(Thread.currentThread().getName()+" ....消费者...."+this.name); flag =false; //2)唤醒所有进程 this.notifyAll(); } } class Productor implements Runnable { private Resources res; Productor(Resources res){ this.res =res; } public void run(){ while(true){ res.set("++商品++"); } } } class Consumer implements Runnable { private Resources res; Consumer(Resources res){ this.res =res; } public void run(){ while(true){ res.out(); } } }
方案2,解决改进1)的问题
升级版:
使用Lock来替换synchronized,wait,notify,nonifyAll语法和语句的使用
不需要同步,不需要notify
记得需要导包:
java.util.concurrent.locks
主要改动:
自定义锁 ---》 Condition对象 --》signallAll
condition.await() === try{this.wait();}catch(Exception e){}
synchronized删除,异常抛出,使用finally解锁
1 /* 2 3 本程序致力于解决多出现多个生产者,多个消费者的时候,依然能够达到生产一次,消费一次的功能 4 : 5 解决的方法就是:1)在被唤醒之后仍然进行条件判断,去检查要改的数字是否满足条件,如果不满足条件就继续睡眠。把两个方法中的if改为while即可。 6 当然,此时仍会出现问题,就是所以线程都等待,失去资格 7 2)需要将notify()改成notifyAll() 8 9 升级版: 10 使用Lock来替换synchronized,wait,notify,nonifyAll语法和语句的使用 11 不需要同步,不需要notify 12 */ 13 import java.util.concurrent.locks.*; 14 class ProducterConsumerDemo3 15 { 16 public static void main(String[] args) 17 { 18 Resources r =new Resources(); 19 Productor pro =new Productor(r); 20 Consumer con = new Consumer(r); 21 22 Thread t1 =new Thread(pro); 23 Thread t2 =new Thread(pro);//多个生产者 24 Thread t3 =new Thread(con); 25 Thread t4 =new Thread(con);//多个消费者 26 t1.start(); 27 t2.start(); 28 t3.start(); 29 t4.start(); 30 System.out.println("Hello World!"); 31 } 32 } 33 34 class Resources 35 { 36 private String name; 37 private int count =1; 38 private boolean flag =false; 39 private Lock lock = new ReentrantLock(); 40 41 private Condition condition = lock.newCondition(); 42 43 public void set(String name) throws InterruptedException 44 { 45 lock.lock(); 46 try 47 { 48 //1)循环判断 49 while(flag) 50 //如果为真,放弃资格 51 condition.await(); //会抛出异常 52 this.name = name+"--"+count++; 53 54 System.out.println(Thread.currentThread().getName()+"生产者"+this.name); 55 flag =true; 56 //2)使用condition唤醒所有进程 57 condition.signalAll(); //如果使用condition.signal()会出现相互等待状况,都失去资格 58 } 59 finally 60 { 61 lock.unlock(); 62 } 63 64 65 } 66 public void out() throws InterruptedException 67 { 68 lock.lock(); 69 try 70 { 71 //1)循环判断 72 while(!flag) 73 condition.await(); 74 75 System.out.println(Thread.currentThread().getName()+" ....消费者...."+this.name); 76 flag =false; 77 //2)使用condition唤醒所有进程 78 condition.signalAll(); 79 } 80 finally //防止当前线程拿到锁后抛异常一直不释放锁 81 { 82 lock.unlock(); 83 } 84 85 86 } 87 } 88 89 class Productor implements Runnable 90 { 91 private Resources res; 92 Productor(Resources res){ 93 this.res =res; 94 } 95 public void run(){ 96 while(true){ 97 try 98 { 99 res.set("++商品++"); //需要抛出异常 100 } 101 catch (InterruptedException e) 102 { 103 } 104 105 } 106 } 107 108 } 109 110 class Consumer implements Runnable 111 { 112 private Resources res; 113 Consumer(Resources res){ 114 this.res =res; 115 } 116 public void run(){ 117 while(true){ 118 try 119 { 120 res.out(); //需要抛出异常 121 } 122 catch (InterruptedException e) 123 { 124 } 125 126 } 127 } 128 129 }
此时实现功能和方案1功能一样
方案3,在方案2的基础上解决改进2)的问题
加强升级版:
此版本为最终版,主要在使用锁lock的基础上,加上唤醒对方(不包括己方)进程的优化
1 /* 2 3 本程序致力于解决多出现多个生产者,多个消费者的时候,依然能够达到生产一次,消费一次的功能 4 : 5 解决的方法就是:1)在被唤醒之后仍然进行条件判断,去检查要改的数字是否满足条件,如果不满足条件就继续睡眠。把两个方法中的if改为while即可。 6 当然,此时仍会出现问题,就是所以线程都等待,失去资格 7 2)需要将notify()改成notifyAll() 8 9 升级版: 10 使用Lock来替换synchronized,wait,notify,nonifyAll语法和语句的使用 11 不需要同步,不需要notify 12 ------------ 13 加强升级版: 14 此版本为最终版,主要在使用锁lock的基础上,加上唤醒对方(不包括己方)进程的优化 15 通过一个锁建立多个condition对象来解决 16 17 流程: 18 生产者拿到锁,执行,判断没有真,继续执行,生产完毕后唤醒消费者来消费 生产者唤醒消费者 19 消费者拿到锁,执行,判断没有假,继续执行,消费完毕后唤醒生产者继续生产 消费者唤醒生产者 20 21 */ 22 import java.util.concurrent.locks.*; 23 class ProducterConsumerDemo4 24 { 25 public static void main(String[] args) 26 { 27 Resources r =new Resources(); 28 Productor pro =new Productor(r); 29 Consumer con = new Consumer(r); 30 31 Thread t1 =new Thread(pro); 32 Thread t2 =new Thread(pro);//多个生产者 33 Thread t3 =new Thread(con); 34 Thread t4 =new Thread(con);//多个消费者 35 t1.start(); 36 t2.start(); 37 t3.start(); 38 t4.start(); 39 System.out.println("Hello World!"); 40 } 41 } 42 43 class Resources 44 { 45 private String name; 46 private int count = 1; 47 private boolean flag =false; 48 private Lock lock = new ReentrantLock(); 49 50 private Condition condition_pro = lock.newCondition(); //使用lock建立生产者的condition对象 51 private Condition condition_con = lock.newCondition(); //使用lock建立消费者的condition对象 52 53 public void set(String name) throws InterruptedException 54 { 55 lock.lock(); 56 try 57 { 58 //1)循环判断 59 while(flag) 60 //如果为真,放弃生产者的资格 61 condition_pro.await(); //会抛出异常 62 this.name = name+"--"+count++; 63 64 System.out.println(Thread.currentThread().getName()+"生产者"+this.name); 65 flag =true; 66 //2)使用消费condition唤醒进程 67 condition_con.signal(); //生产者生产完毕后,唤醒消费者的进程(不再是signalAll) 68 } 69 finally 70 { 71 lock.unlock(); 72 } 73 74 75 } 76 public void out() throws InterruptedException 77 { 78 lock.lock(); 79 try 80 { 81 //1)循环判断 82 while(!flag) 83 //如果为假,放弃消费者的资格 84 condition_con.await(); 85 86 System.out.println(Thread.currentThread().getName()+" ....消费者...."+this.name); 87 flag =false; 88 //2)使用生产者condition唤醒进程 89 condition_pro.signal(); //消费者消费完毕后,唤醒生产者的进程 90 } 91 finally //防止当前线程拿到锁后抛异常一直不释放锁 92 { 93 lock.unlock(); 94 } 95 96 97 } 98 } 99 100 class Productor implements Runnable 101 { 102 private Resources res; 103 Productor(Resources res){ 104 this.res =res; 105 } 106 public void run(){ 107 while(true){ 108 try 109 { 110 res.set("++商品++"); //需要抛出异常 111 } 112 catch (InterruptedException e) 113 { 114 } 115 116 } 117 } 118 119 } 120 121 class Consumer implements Runnable 122 { 123 private Resources res; 124 Consumer(Resources res){ 125 this.res =res; 126 } 127 public void run(){ 128 while(true){ 129 try 130 { 131 res.out(); //需要抛出异常 132 } 133 catch (InterruptedException e) 134 { 135 } 136 137 } 138 } 139 140 }
图示: