经典的生产与消费线程同步问题
2012-03-26 10:44
162 查看
java code:
我的问题是, push 和 pop 中的 while 可不可以用 if 代替,如果不可以是不是这样理解的:假设是生产被暂停了,转到消费,当生产被唤醒,下次转到生产时是不是从被暂停的地方开始,就是 this.wait() 那里开始,还是重新执行 run(),从头开始,如果是这样的话,好像 while 就不能 if 替代了。不知道我的理解对不对?
回复1:
用while是为了防止你的pop,push不是被对方唤醒的。因为你的synchronized 用的是当前对象,有可能它在其它地方也作为一个锁。
所以,你用notify也不对,应该用notifyAll。
回复2:
线程唤醒后是从wait()后边的语句执行。一楼说的有道理“用while是为了防止你的pop,push不是被对方唤醒的。”。
我认为,就楼主的程序,没必要用notifyAll(). 也可以用if.
回复3:
这个,我仔细想了想,从逻辑上说这个应该不能用if代替while,因为当被唤醒后,理论上应该再次判断是否栈是满的(或是空的),这个貌似if只判断一次,虽然在这里好像没什么区别,但逻辑上应该是这样的,就像
1楼 说的可能是被别的什么唤醒的,那么很显然就会有问题了。不知道 1楼 的是不是这个意思。至于,notify和notifyAll的话,在这个问题中,线程只有两个,所以,用哪个应该都没有区别把.
回复4:
不能用if,用while用if的话,那个线程被唤醒,马上就会去运行,不会再次检测了,而且lz的try
catch 最好写在while循环之外,因为那样即使发生异常,程序还会在循环中运行。
回复5:
“用if的话,那个线程被唤醒,马上就会去运行,不会再次检测了”
这个应该不可能。 线程唤醒后,会从"Object's wait pool" 进入"Object's lock pool",
那个执行了"notify()的线程还在synchronized 方法里,还继续占着锁不释放。直到它执行完,才会释放锁,被唤醒线程才有机会执行。不会象楼上说的 “马上去执行”。
回复6:
学习了,确实觉得是为了在被其他的线程唤醒的时候,能再度wait。且使用notify也确实不对,如果notify了一个线程,而这个线程发现不是自己想要的数据唤醒的自己,所以就会wait,这样就浪费了一次“唤醒”的机会。最后将会死锁。
所以用notifyAll是有必要的。
class SynStack { private char[] data = new char[6]; private int cnt = 0; //表示数组有效元素的个数 public synchronized void push(char ch) { while (cnt == data.length) { try { this.wait(); } catch (Exception e) { } } this.notify(); data[cnt] = ch; ++cnt; System.out.printf("生产线程正在生产第%d个产品,该产品是: %c\n", cnt, ch); } public synchronized char pop() { char ch; while (cnt == 0) { try { this.wait(); } catch (Exception e) { } } this.notify(); ch = data[cnt-1]; System.out.printf("消费线程正在消费第%d个产品,该产品是: %c\n", cnt, ch); --cnt; return ch; } } class Producer implements Runnable { private SynStack ss = null; public Producer(SynStack ss) { this.ss = ss; } public void run() { char ch; for (int i=0; i<20; ++i) { ch = (char)('a'+i); ss.push(ch); } } } class Consumer implements Runnable { private SynStack ss = null; public Consumer(SynStack ss) { this.ss = ss; } public void run() { for (int i=0; i<20; ++i) { try{ Thread.sleep(100); } catch (Exception e){ } ss.pop(); } } } public class TestPC { public static void main(String[] args) { SynStack ss = new SynStack(); Producer p = new Producer(ss); Consumer c = new Consumer(ss); Thread t1 = new Thread(p); t1.start(); Thread t2 = new Thread(c); t2.start(); } }
我的问题是, push 和 pop 中的 while 可不可以用 if 代替,如果不可以是不是这样理解的:假设是生产被暂停了,转到消费,当生产被唤醒,下次转到生产时是不是从被暂停的地方开始,就是 this.wait() 那里开始,还是重新执行 run(),从头开始,如果是这样的话,好像 while 就不能 if 替代了。不知道我的理解对不对?
回复1:
用while是为了防止你的pop,push不是被对方唤醒的。因为你的synchronized 用的是当前对象,有可能它在其它地方也作为一个锁。
所以,你用notify也不对,应该用notifyAll。
回复2:
线程唤醒后是从wait()后边的语句执行。一楼说的有道理“用while是为了防止你的pop,push不是被对方唤醒的。”。
我认为,就楼主的程序,没必要用notifyAll(). 也可以用if.
回复3:
这个,我仔细想了想,从逻辑上说这个应该不能用if代替while,因为当被唤醒后,理论上应该再次判断是否栈是满的(或是空的),这个貌似if只判断一次,虽然在这里好像没什么区别,但逻辑上应该是这样的,就像
1楼 说的可能是被别的什么唤醒的,那么很显然就会有问题了。不知道 1楼 的是不是这个意思。至于,notify和notifyAll的话,在这个问题中,线程只有两个,所以,用哪个应该都没有区别把.
回复4:
不能用if,用while用if的话,那个线程被唤醒,马上就会去运行,不会再次检测了,而且lz的try
catch 最好写在while循环之外,因为那样即使发生异常,程序还会在循环中运行。
回复5:
“用if的话,那个线程被唤醒,马上就会去运行,不会再次检测了”
这个应该不可能。 线程唤醒后,会从"Object's wait pool" 进入"Object's lock pool",
那个执行了"notify()的线程还在synchronized 方法里,还继续占着锁不释放。直到它执行完,才会释放锁,被唤醒线程才有机会执行。不会象楼上说的 “马上去执行”。
回复6:
学习了,确实觉得是为了在被其他的线程唤醒的时候,能再度wait。且使用notify也确实不对,如果notify了一个线程,而这个线程发现不是自己想要的数据唤醒的自己,所以就会wait,这样就浪费了一次“唤醒”的机会。最后将会死锁。
所以用notifyAll是有必要的。
相关文章推荐
- 生产者消费者问题 这是一个非常经典的多线程题目,题目大意如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个有多个缓冲区的缓冲池,生产者
- 多线程经典问题:馒头问题 生产和消费问题(线程的通信问题)
- Java 线程同步 生产消费问题
- 多线程之偷了个懒之经典生产消费问题
- 生产者消费者问题 这是一个非常经典的多线程题目,题目大意如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个有多个缓冲区的缓冲池,生产者
- 【Java】----线程同步:生产-消费问题
- 线程同步—生产消费问题
- 多线程的经典案例(生产消费问题)
- 生产者消费者问题 这是一个非常经典的多线程题目,题目大意如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个有多个缓冲区的缓冲池,生产者
- 多线程生产消费问题
- Java并发(八)生产消费问题&虚假唤醒
- --多线程中,单生产单消费,多生产多消费的问题
- linux基础——经典线程同步问题解析及编程实现
- 线程 --生产和消费问题
- 经典线程同步互斥问题在windows下的各种解法
- 多线程之生产消费问题
- 条件变量实现生产消费问题
- [Java] Thread-05- 线程同步-生产者与消费者的经典问题
- 信号量解决经典线程同步问题
- java信号量解决生产消费问题