本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处!
上一讲我们让消费者和生产者都各停1毫秒,实际上大多并不是这样的。第二讲,我们讲一个极端的例子和一个正常的例子,假设您已经看过上一讲,我们只改变Consumer和Producer,来看结果。
名词解释
wait:当前线程不运行,处理等待状态,等待notify;所以也不会往下执行。
您可能会有疑问前例中的为什么要用while循环而非if语句?
主要是防止多线程操作时,例桌子已经占满,两个生产线程均处理等待状态,但消费线程通过notifyAll打开其等待状态,就造成生产过量的蛋糕,而导致生产消费模式失败,所以不能用if语句。
sleep:暂停当前线程若干时间,之后继续运行
Special Sample:生产者和消费者均不加sleep
Result:
Produce1 produce:1 Produce2 produce:2 Produce1 produce:3 Produce1 produce:4 Produce1 produce:5 Produce1 begin to wait ! Consumer1 consume:5 Consumer1 consume:4 Consumer1 consume:3 Consumer1 consume:2 Consumer1 consume:1 Consumer1 begin to wait ! Produce1 stop waiting ! Produce1 produce:1Produce1 produce:2 Produce2 produce:3 Produce2 produce:4 Produce2 produce:5 Produce2 begin to wait ! Consumer2 consume:5 Consumer2 consume:4 Consumer2 consume:3 Consumer2 consume:2 Consumer2 consume:1 Consumer2 begin to wait ! Produce2 stop waiting ! Produce2 produce:1 Produce2 produce:2 Produce2 produce:3 Produce2 produce:4 Produce2 produce:5 Produce2 begin to wait ! Produce1 begin to wait ! Consumer1 stop waiting ! Consumer1 consume:5 Consumer1 consume:4 Consumer1 consume:3 Consumer1 consume:2 Consumer1 consume:1 Consumer1 begin to wait ! Produce1 stop waiting ! Produce1 produce:1 Produce1 produce:2 Produce1 produce:3 Produce1 produce:4 Produce1 produce:5 Produce1 begin to wait ! Produce2 stop waiting ! Produce2 begin to wait ! Consumer2 stop waiting ! Consumer2 consume:5 Consumer2 consume:4 Consumer2 consume:3 Consumer2 consume:2 Consumer2 consume:1 Consumer2 begin to wait ! Produce2 stop waiting ! Produce2 produce:1 Produce2 produce:2 Produce2 produce:3 Produce2 produce:4 Produce2 produce:5 Produce2 begin to wait ! Produce1 stop waiting ! Produce1 begin to wait ! Consumer1 stop waiting ! Consumer1 consume:5 Consumer1 consume:4 Consumer1 consume:3 Consumer1 consume:2 Consumer1 consume:1 Consumer1 begin to wait ! Produce1 stop waiting ! Produce1 produce:1 Produce1 stop at last !解析:例子很极端,生产和消费均两个线程,A线程在工作时B在等待;A生产线程生产,B生产线程等待直到A生产完;
A消费线程消费,B消费线程等待直到A消费完;
B生产线程生产,A生产线程等待直到A生产完;
B消费线程消费,A消费线程等待直到A消费完;
……
这样一个循环,失去多线程的意义所在(变成了单线程)!
正常的例子:生产可能只需要1毫秒,消费需要2毫秒
Produce1 produce:1 Consumer1 consume:1 Consumer2 begin to wait !//此时Consumer2检测到count为0,所以等待 Produce2 produce:1 Consumer2 stop waiting !//此时Consumer2检测到count已经大于0,所以打开 Consumer2 consume:1 Produce1 produce:1//看,生产与消费是无序的。两者分开,不管你在不在生产,我都要消费,只要蛋糕还有; Produce2 produce:2//不管你消费不消费,只要桌子还有空的;它们两个均对一种情况负责:桌子和蛋糕形成的映射关系! Consumer2 consume:2 Consumer1 consume:1 Produce2 produce:1 Produce1 produce:2 Produce2 produce:3 Produce1 produce:4 Consumer1 consume:4 Consumer2 consume:3 Produce1 produce:3 Produce2 produce:4 Produce2 produce:5 Produce1 begin to wait ! Consumer1 consume:5 Produce1 stop waiting ! Produce1 produce:5 Produce2 begin to wait ! Consumer2 consume:5 Produce2 stop waiting ! Produce2 produce:5 Produce2 begin to wait ! Produce1 begin to wait ! Consumer2 consume:5 Produce1 stop waiting ! Produce1 produce:5 Produce2 stop waiting ! Produce2 begin to wait ! Consumer1 consume:5 Produce2 stop waiting ! Produce2 produce:5 Produce1 begin to wait ! Produce2 begin to wait ! Consumer1 consume:5 Consumer1 stop at last !解析:这次我让执行25次即退出虚拟机。大家可以看到,本次两个生产线程和两个消费线程,在生产和消费的时候都是无序的,无论你要不要停,我都要工作,不能让一个线程一直抓住锁不放,其实这才是多线程本质。
代码如下:
Producer:
public class Producer extends Thread { Table table; String threadName; public Producer(String string, Table table) { // TODO Auto-generated constructor stub this.table = table; this.threadName = string; this.setName(threadName); } @Override public void run() { // TODO Auto-generated method stub super.run(); try { while (true) { table.produce(threadName); sleep(1); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
消费者:
public class Consumer extends Thread { Table table; String threadName; public Consumer(String string, Table table) { // TODO Auto-generated constructor stub this.table = table; this.threadName = string; this.setName(threadName); } @Override public void run() { // TODO Auto-generated method stub super.run(); try { while (true) { table.consume(threadName); sleep(2); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }