gpt4 book ai didi

java - 同步实现 : Java

转载 作者:行者123 更新时间:2023-11-30 07:04:35 27 4
gpt4 key购买 nike

这是一个消费者-生产者问题,我希望得到如下输出:
放:0
得到:0
放:1
获得:1
....等等。
但与此相反,尽管使用了 wait() 和 notify() 方法,但 Consumer 类多次使用相同的 q 值,而且 Producer 类会超过消费者。如何获得同步输出?

这是 QFixed 类:(定义了 put() 和 get() 方法)

class QFixed{
int n;
boolean valueset = false;

synchronized int get(){
if(!valueset){
try {
wait();
} catch (InterruptedException ex) {
System.out.println("interrupted");
}
}
System.out.println("Got: " +n);
valueset = false;
notify();
return n;
}

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

这是 ProducerFixed 类:

class ProducerFixed implements Runnable{
Q q;
Thread t;
public volatile boolean flag = true;
ProducerFixed(Q q){
this.q = q;
t = new Thread(this,"Producer");
t.start();
}

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

void stop() {
flag = false;
}
}

这是 ConsumerFixed 类:

class ConsumerFixed implements Runnable{
Q q;
Thread t;
public volatile boolean flag = true;

ConsumerFixed(Q q){
this.q = q;
t = new Thread(this,"Consumer");
t.start();
}

@Override
public void run(){
while(flag){
q.get();
}
}

public void stop() {
flag = false;
}
}

这是 Producer_Consumer_Fixed 类:

public class Producer_Consumer_Fixed {
public static void main(String arg[]){
Q q = new Q();
Producer p = new Producer(q);
Consumer c = new Consumer(q);

try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("interrupted");
}

p.stop();
c.stop();
try{
p.t.join();
c.t.join();
}catch(InterruptedException e){
System.out.println("interrupted");
}
}
}

最佳答案

if (flag) wait 的 QFixed get 和 put 方法中使用的习语已损坏,您应该改用 while 循环。参见 the Oracle tutorial on guarded blocks .

一旦我更改了类的名称以删除“Fixed”,并在 Q 类中将 if 替换为 while,如下所示:

class Q {
int n;
boolean valueset = false;

synchronized int get(){
while(!valueset){
try {
wait();
} catch (InterruptedException ex) {
System.out.println("interrupted");
}
}
System.out.println("Got: " +n);
valueset = false;
notify();
return n;
}

synchronized void put(int n){
while (valueset){
try {
wait();
} catch (InterruptedException ex) {
System.out.println("interrupted");
}
}
this.n = n;
valueset = true;
System.out.println("Put: "+n);
notify();
}
}

我的输出开始于

Put: 0
Got: 0
Put: 1
Got: 1
Put: 2
Got: 2
Put: 3
Got: 3
Put: 4
Got: 4
Put: 5
Got: 5
Put: 6
Got: 6
Put: 7
Got: 7
Put: 8
Got: 8
Put: 9
Got: 9
Put: 10
Got: 10
...

每个值被放置和获取一次,这是您想要的输出。

使用 while 循环是一件好事有几个原因。

等待线程放弃监视器,一旦它醒来,它必须重新获取监视器才能继续退出等待方法。这意味着其他线程可以获取监视器并可能更改同步所保护的数据的状态。一旦线程重新获取监视器,它需要再次检查条件,然后才能知道它认为它收到通知的条件是否实际发生了。否则线程将根据过时的信息决定要做什么。

在涉及三个或更多竞争线程的示例中,这将是一个大问题。但是,对于这个特定案例,我没有看到有问题的操作顺序。

while 循环的另一个原因是,仅仅因为线程退出等待并不一定意味着发生了通知。根据javadoc for Object#wait :

A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops, like this one:

synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}

这来自 JVM 实现中的竞争条件;如文档所述,这应该很少见。但这可能是这里问题的根源,等待返回而没有得到通知可能会产生多次获取的情况,就像您看到的那样。

关于java - 同步实现 : Java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27564844/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com