关于java多线程的一个生产者和多个消费者

hahaha66 2010-04-26 04:19:26
代码如下:
class Q {
int n;
private boolean p = false;

synchronized int get() {
if (!p) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Get: " + n);
p = false;
notify();
return n;
}

synchronized void put(int n) {
if (p)
try {
wait();
} catch (InterruptedException e) {
System.out.println("InterruptedException caught");
}
this.n = n;
System.out.println("Put: " + n);
p = true;
notify();
}
}

class Producer implements Runnable {
Q q;

Producer(Q q) {
this.q = q;
new Thread(this, "Producer").start();
}

public void run() {
int i = 0;
while (true) {
q.put(i++);
}
}
}

class Consumer implements Runnable {
Q q;

Consumer(Q q) {
this.q = q;
new Thread(this, "Consumer1").start();
new Thread(this, "Consumer2").start();
new Thread(this, "Consumer3").start();
}

public void run() {
synchronized (q) {
while (true) {
q.get();
}
}
}
}

class PC {
public static void main(String args[]) {
Q q = new Q();
Thread thread = Thread.currentThread();
new Producer(q);
new Consumer(q);
try {
thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Press Control-C to stop.");
}
}
...全文
1655 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
haoren_e 2011-01-21
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 hq1305018 的回复:]
我把你的代码改了一下.请参考

Java code

class Q {
int n;

private boolean p = false;

synchronized int get() {
while (!p) {
try {
wait();
} ……
[/Quote]

很对头
chan10 2010-06-02
  • 打赏
  • 举报
回复
生产者消费者模式弄明白了,多线程,同步问题,也就了解了大半了。
jiahuafu 2010-04-28
  • 打赏
  • 举报
回复
楼主的问题经典啊!我都不会弄呵呵

j2se,多线程,socket网络,JBoss Netty研究群15161096
欢迎加入!
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 hahaha666 的回复:]

引用 19 楼 bao110908 的回复:
回复了这么多,竟然 1 分都没得

我给错人了,我怎么给potahai 给了25分,我是要给你的
[/Quote]

呵呵,没关系的,反正我也不缺分

这个帖子涉及线程知识点不错,共同学习一下吧。
hahaha66 2010-04-28
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 bao110908 的回复:]
回复了这么多,竟然 1 分都没得
[/Quote]
我给错人了,我怎么给potahai 给了25分,我是要给你的
hahaha66 2010-04-28
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 byhsh 的回复:]
楼主是在做东西吗!
[/Quote]
不是的,是最近没事在研究一下
byhsh 2010-04-27
  • 打赏
  • 举报
回复
楼主是在做东西吗!
WilliamTau 2010-04-27
  • 打赏
  • 举报
回复
线程要锁定
  • 打赏
  • 举报
回复
回复了这么多,竟然 1 分都没得
  • 打赏
  • 举报
回复
这里加同步没有什么意义,因为 q.get 方法已经同步过了。而且这个同步块中也没有什么共享变量。

如果你使用的是我第一次给你的那代码的话,就不会产生问题了。我在用 ReentrantLock 测试时,是把 while(true) 这里的同步给去掉了,忘记说了,呵呵。

你加上这句后一直执第一个线程,那可能是你使用了带有 ReentrantLock 和 Condition 的代码。由于使用锁不同,这个 while(true) 要加同步的话,也必须是 ReentrantLock 的那把锁。如果再使用 q 锁,由于其他地方没有在 q 锁上的 wait,导致 q 锁永远不会被释放,因此只有一个线程在运行了。

如果使用可重入锁做的话,而且又有必要在 while(true) 这里加上同步的话,那么可以这样改一下:

class Consumer implements Runnable {
Q q;

Consumer(Q q) {
this.q = q;
new Thread(this, "Consumer1").start();
new Thread(this, "Consumer2").start();
new Thread(this, "Consumer3").start();
}

public void run() {
// 使用 Q 中的 ReentrantLock 锁
// 把 Q 中 lock 的 private 去掉,变成包内可访问
q.lock.lock();
try {
while (true) {
q.get();
}
} finally {
// Lock 接口的锁必须在 finally 中释放掉,便于在有异常时也能正常的释放锁,以免造成死锁
// 而用 synchronized 的话,在抛出异常时 JVM 会自动释放锁
q.lock.unlock();
}
}
}




hahaha66 2010-04-26
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 hahaha666 的回复:]
synchronized (q) {
while (true) {
q.get();
}
我加上了这句后就一直只执行第一个线程,其他的两个就不执行了
[/Quote]
我的本意是要让他们三个线程只有一个可以拿
potahai 2010-04-26
  • 打赏
  • 举报
回复
留名```学习
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 hahaha666 的回复:]
synchronized (q) {
while (true) {
q.get();
}
我加上了这句后就一直只执行第一个线程,其他的两个就不执行了
[/Quote]

这里干嘛要去加同步啊?
hahaha66 2010-04-26
  • 打赏
  • 举报
回复
synchronized (q) {
while (true) {
q.get();
}
我加上了这句后就一直只执行第一个线程,其他的两个就不执行了
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 hahaha666 的回复:]

Condition 是不是信号量?还有在我的实现方式中的
synchronized (q) {
while (true) {
q.get();
}
}
是不是可以不要。还有wait()方法被激活后是不是就往下执行了,不会再重新开始执行函数了吗?谢谢了。。。线程没学好啊。。。呵呵
[/Quote]

不能不要!

wait() 被唤醒后,会接着执行,而不是从头开始执行。
zings 2010-04-26
  • 打赏
  • 举报
回复
看高手指点。。。
  • 打赏
  • 举报
回复
Condition 是一个等待、唤醒的条件变量,呵呵。

用 wait, notifyAll 的话,你可能也注意到了,当某个消费线程消费完了,使用 notify 或者 notifyAll 唤醒其他线程。其实我们的本意唤醒生产线程就可以了,但是 notify 或者 notifyAll 并不一定会去唤醒生产线程,被唤醒的有可能是另一个消费线程,这样的话将会导致很多的无用功,浪费系统资源。如果不用 notifyAll,而把上面的代码改成 notify 的话,那会使用生产/消费速度变得奇慢无比,就是这个原因造成的。

用 Condition 的话,我们可以从可重入锁中产生两个条件变量,一个用于生产线程,一个用于消费线程。当消费线程消费完了之后,我们只要唤醒生产线程就可以了,没必要去唤醒消费线程。
hahaha66 2010-04-26
  • 打赏
  • 举报
回复
还有我的get()方法中用notify()有问题吗?我只要激活我的put()方法就行了
hahaha66 2010-04-26
  • 打赏
  • 举报
回复
Condition 是不是信号量?还有在我的实现方式中的
synchronized (q) {
while (true) {
q.get();
}
}
是不是可以不要。还有wait()方法被激活后是不是就往下执行了,不会再重新开始执行函数了吗?谢谢了。。。线程没学好啊。。。呵呵
零起跑线 2010-04-26
  • 打赏
  • 举报
回复
java多线程还没概念,来学习一下
加载更多回复(7)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧