一、一生产一消费:操作值
等待、通知模式最经典的案例是“生产者/消费者” 模式,但此模式
在使用上有几种变形,有一些小的注意事项,但原理都是wait/notify
package com.it.po.thread9; public class P { private String lock; public P(String lock) { this.lock = lock; } public void setValue(){ try { synchronized (lock) { if(!ValueObject1.value.equals("")){//先等着 lock.wait(); } String value=System.currentTimeMillis()+"_"+System.nanoTime(); System.out.println("set value= "+value); ValueObject1.value=value; lock.notify();//通知取值 } } catch (InterruptedException e) { e.printStackTrace(); } } }
package com.it.po.thread9; public class S { private String lock; public S(String lock) { this.lock = lock; } public void getValue(){ try { synchronized (lock) { if("".equals(ValueObject1.value)){//没值先等着 lock.wait(); } System.out.println("get Value= "+ValueObject1.value); ValueObject1.value=""; lock.notify(); } } catch (InterruptedException e) { e.printStackTrace(); } } }
package com.it.po.thread9; import java.util.ArrayList; import java.util.List; public class ValueObject1 { public static String value=""; }
package com.it.po.thread9; public class MyThread2_2 extends Thread { private String lock; public MyThread2_2(String lock) { this.lock = lock; } @Override public void run() { super.run(); while (true){ new P(lock).setValue(); } } }
package com.it.po.thread9; public class MyThread2_1 extends Thread { private String lock; public MyThread2_1(String lock) { this.lock = lock; } @Override public void run() { super.run(); while (true) { new S(lock).getValue(); } } }
package com.it.po.thread9; public class Run6 { public static void main(String[] args) throws InterruptedException { String lock = "po"; MyThread2_1 my1 = new MyThread2_1(lock); MyThread2_2 my2 = new MyThread2_2(lock); my2.start(); my1.start(); } }
set value= 1574692190737_1636737500969725 get Value= 1574692190737_1636737500969725 set value= 1574692190737_1636737501017240 get Value= 1574692190737_1636737501017240 set value= 1574692190737_1636737501065834 get Value= 1574692190737_1636737501065834 set value= 1574692190737_1636737501114428 get Value= 1574692190737_1636737501114428 set value= 1574692190737_1636737501163563 get Value= 1574692190737_1636737501163563 set value= 1574692190737_1636737501213237 get Value= 1574692190737_1636737501213237
二、多个生产者和多个消费者的情况
以上是一个生产者和一个消费者,如果是多个生产者和多个消费者
则可能出现假死的情况,也就是多个线程出现waiting等待状态。
如果全部线程进入waiting状态,那么程序就不再执行任何业务功能了。
整个项目呈停止状态
(一)、假死状态
package com.it.po.thread9; public class P2 { private String lock; public P2(String lock) { this.lock = lock; } public void setValue(){ try { synchronized (lock) { while(!ValueObject1.value.equals("")){//先等着 System.out.println(Thread.currentThread().getName()+" waiting"); lock.wait(); } System.out.println(Thread.currentThread().getName()+" runnable"); String value=System.currentTimeMillis()+"_"+System.nanoTime(); ValueObject1.value=value; lock.notify();//通知取值 } } catch (InterruptedException e) { e.printStackTrace(); } } }
package com.it.po.thread9; public class S2 { private String lock; public S2(String lock) { this.lock = lock; } public void getValue(){ try { synchronized (lock) { while ("".equals(ValueObject1.value)){//没值先等着 System.out.println(Thread.currentThread().getName()+" waiting"); lock.wait(); } System.out.println(Thread.currentThread().getName()+" running"); ValueObject1.value=""; lock.notify(); } } catch (InterruptedException e) { e.printStackTrace(); } } }


package com.it.po.thread9; public class Run7 { public static void main(String[] args) throws InterruptedException { String lock="lanpo"; P2 p2 = new P2(lock); S2 s2 = new S2(lock); Thread3_1 my1 = new Thread3_1(p2); Thread3_2 my2 = new Thread3_2(p2); Thread3_3 my3 = new Thread3_3(s2); Thread3_4 my4 = new Thread3_4(s2); my1.setName("1 号 生产者"); my2.setName("2 号 生产者"); my3.setName("1 号 消费者"); my4.setName("2 号 消费者"); my1.start(); my2.start(); my3.start(); my4.start(); Thread.sleep(2000); Thread[] threads = new Thread[Thread.currentThread().getThreadGroup().activeCount()]; Thread.currentThread().getThreadGroup().enumerate(threads); for(int i=0;i<threads.length;i++){ System.out.println(threads[i].getName()+" "+threads[i].getState()); } } }


四个线程都呈 假死状态(waiting)
左边是序号:下面的前面数字都是序号
1. 1号消费者发现value为空,只能等,准备唤醒异类线程 1号生产者
2. 1号生产者生产完,放弃锁,但是run方法中是while 又马上获取锁,进入了
setValue 方法中的while 然后waiting
3. 1号生产者唤醒同类线程生产者2号
。。。
同理分析到 8,9
10. 这一步是关键,在两个生产者都处于waiting的时候,消费者又唤醒同类
最终导致四个线程处于waiting。。。
(二)、解决假死状态
将notify 都变成notifyAll即可
package com.it.po.thread9; public class S2 { private String lock; public S2(String lock) { this.lock = lock; } public void getValue(){ try { synchronized (lock) { while ("".equals(ValueObject1.value)){//没值先等着 System.out.println(Thread.currentThread().getName()+" waiting"); lock.wait(); } System.out.println(Thread.currentThread().getName()+" running"); ValueObject1.value=""; lock.notifyAll(); } } catch (InterruptedException e) { e.printStackTrace(); } } }
package com.it.po.thread9; public class P2 { private String lock; public P2(String lock) { this.lock = lock; } public void setValue(){ try { synchronized (lock) { while(!ValueObject1.value.equals("")){//先等着 System.out.println(Thread.currentThread().getName()+" waiting"); lock.wait(); } System.out.println(Thread.currentThread().getName()+" runnable"); String value=System.currentTimeMillis()+"_"+System.nanoTime(); ValueObject1.value=value; lock.notifyAll();//通知取值 } } catch (InterruptedException e) { e.printStackTrace(); } } }

程序一直运行。。。
三、一生产与多消费 操作栈
生产者向堆栈List对象中放入数据
使消费者从堆栈中List取数据List最大容量是1
(一)先看一生产者对一消费者
package com.it.po.thread10; import java.util.ArrayList; import java.util.List; public class MyStack { private List list =new ArrayList(); synchronized public void push(){ try { if(list.size()==1) { System.out.println(Thread.currentThread().getName() +" waiting"); this.wait(); //this就是当前对象 } System.out.println(Thread.currentThread().getName() +" runnable"); list.add(System.nanoTime()); this.notify(); System.out.println("push size() "+list.size()); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized public void pop(){//取出 try { if(list.size()==0) { System.out.println(Thread.currentThread().getName() +" waiting"); this.wait(); } System.out.println(Thread.currentThread().getName() +" runnable"); list.remove(0); this.notify(); System.out.println("pop size() "+list.size()); } catch (InterruptedException e) { e.printStackTrace(); } } }

package com.it.po.thread10; import com.it.po.thread9.MyThread1_1; import com.it.po.thread9.MyThread1_2; import com.it.po.thread9.MyThread1_3; import com.it.po.thread9.NotifyThread1_4; public class Run1 { public static void main(String[] args) throws InterruptedException { MyStack myStack = new MyStack(); Thread1_1 my1 = new Thread1_1(myStack); Thread1_2 my2 = new Thread1_2(myStack); my1.setName("生产者 "); my2.setName("消费者 "); my1.start(); my2.start(); } }
消费者 waiting 生产者 runnable push size() 1 生产者 waiting 消费者 runnable pop size() 0 消费者 waiting 生产者 runnable push size() 1 生产者 waiting 消费者 runnable pop size() 0 消费者 waiting
一直执行。。。
(二)、一生产者对多个消费者

package com.it.po.thread10; import com.it.po.thread9.MyThread1_1; import com.it.po.thread9.MyThread1_2; import com.it.po.thread9.MyThread1_3; import com.it.po.thread9.NotifyThread1_4; public class Run1 { public static void main(String[] args) throws InterruptedException { MyStack myStack = new MyStack(); Thread1_1 my1 = new Thread1_1(myStack); Thread1_2 my2 = new Thread1_2(myStack); Thread1_3 my3= new Thread1_3(myStack); Thread1_4 my4 = new Thread1_4(myStack); my1.setName("生产者 "); my2.setName("1 号消费者 "); my3.setName("2 号消费者 "); my4.setName("3 号消费者 "); my1.start(); my2.start(); my3.start(); my4.start(); } }
1 号消费者 waiting 2 号消费者 waiting 生产者 runnable push size() 1 生产者 waiting 1 号消费者 runnable pop size() 0 1 号消费者 waiting 2 号消费者 runnable 3 号消费者 waiting Exception in thread "2 号消费者 " java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 at java.util.ArrayList.rangeCheck(ArrayList.java:653) at java.util.ArrayList.remove(ArrayList.java:492) at com.it.po.thread10.MyStack.pop(MyStack.java:30) at com.it.po.thread10.Thread1_3.run(Thread1_3.java:11)


解决办法
package com.it.po.thread10; import java.util.ArrayList; import java.util.List; public class MyStack { private List list =new ArrayList(); synchronized public void push(){ try { while (list.size()==1) { System.out.println(Thread.currentThread().getName() +" waiting"); this.wait(); } System.out.println(Thread.currentThread().getName() +" runnable"); list.add(System.nanoTime()); this.notify(); System.out.println("push size() "+list.size()); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized public void pop(){//取出 try { while (list.size()==0) { System.out.println(Thread.currentThread().getName() +" waiting"); this.wait(); } System.out.println(Thread.currentThread().getName() +" runnable"); list.remove(0); this.notify(); System.out.println("pop size() "+list.size()); } catch (InterruptedException e) { e.printStackTrace(); } } }
if都改成while

生产者 runnable push size() 1 生产者 waiting 3 号消费者 runnable pop size() 0 3 号消费者 waiting 2 号消费者 waiting 1 号消费者 waiting
程序呈假死状态。
最终解决办法 : notify 改成notifyAll
package com.it.po.thread10; import java.util.ArrayList; import java.util.List; public class MyStack { private List list =new ArrayList(); synchronized public void push(){ try { while (list.size()==1) { System.out.println(Thread.currentThread().getName() +" waiting"); this.wait(); } System.out.println(Thread.currentThread().getName() +" runnable"); list.add(System.nanoTime()); this.notifyAll(); System.out.println("push size() "+list.size()); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized public void pop(){//取出 try { while (list.size()==0) { System.out.println(Thread.currentThread().getName() +" waiting"); this.wait(); } System.out.println(Thread.currentThread().getName() +" runnable"); list.remove(0); this.notifyAll(); System.out.println("pop size() "+list.size()); } catch (InterruptedException e) { e.printStackTrace(); } } }

一直执行。。。。
总结:
同理:多生产和一消费,多生产和多消费参考上面即可。
浙公网安备 33010602011771号