[英]Why sometimes in the output of the producer-consumer problem, the consumer is getting a previous value instead of the new value produced by producer?
I have this below Java code:我有下面的 Java 代码:
class Q2 {
int n;
boolean valueSet = false;
synchronized int get() {
while(!valueSet)
try {
System.out.println("Consumer waiting ...");
wait();
}
catch(InterruptedException e) {
System.err.println("InterruptedException caught");
}
System.out.println("Consumer awakened");
System.out.println("Got: "+n);
valueSet = false;
notify();
System.out.println("Consumer called notify()");
return n;
}
synchronized void put(int n) {
while(valueSet)
try {
System.out.println("Producer waiting ...");
wait();
}
catch(InterruptedException e) {
System.err.println("InterruptedException caught");
}
System.out.println("Producer awakened");
System.out.println("Before put n is: " + this.n);
this.n = n;
valueSet = true;
System.out.println("Put: " + this.n);
notify();
System.out.println("Producer called notify()");
}
}
class Producer2 implements Runnable {
Q2 q;
int noOfTimes;
Producer2(Q2 q) {
this.q = q;
new Thread(this, "Producer").start();
}
public void run() {
int i=0;
noOfTimes=0;
while(q.n < 2) {
q.put(i++);
noOfTimes++;
}
System.out.println("Producer ran: " + noOfTimes + " times.");
}
}
class Consumer2 implements Runnable {
Q2 q;
int noOfTimes;
Consumer2(Q2 q) {
this.q = q;
new Thread(this, "Consumer").start();
}
public void run() {
int i=0;
noOfTimes=0;
while(q.n < 2) {
System.out.println("Iteration " + (noOfTimes+1) + "; Before get() n is: " + q.n);
int val = q.get();
System.out.println("After get() n is: " + q.n);
noOfTimes++;
}
System.out.println("Consumer ran: " + noOfTimes + " times.");
System.out.println("n: " + q.n);
}
}
public class PCFixed {
public static void main(String[] args) {
Q2 q = new Q2();
new Producer2(q);
new Consumer2(q);
}
}
One particular output:一个特定的输出:
Producer awakened
Before put n is: 0 // because n is int and default value of n is 0
Put: 0 // instance variable n associated with object of Q2 is set to 0
Producer called notify() // no effect
Producer waiting ... // thread spawned from Producer waits
Iteration 1; Before get() n is: 0 // context switching to thread spawned from Consumer
Consumer awakened
Got: 0
Consumer called notify()
After get() n is: 0
Iteration 2; Before get() n is: 0
Producer awakened // context switching to Producer's thread
Before put n is: 0
Put: 1
Producer called notify()
Producer waiting ... // Producer's thread waits/sleeps
Consumer awakened // context switching to Consumer's thread
Got: 1
Consumer called notify()
After get() n is: 1
Producer awakened // context switching to Producer's thread
Before put n is: 1
Put: 2 // #### line 1
Producer called notify()
Iteration 3; Before get() n is: 1 // #### line 2: context switching to Consumer's thread
Producer ran: 3 times. // context switching to Producer's thread
Consumer awakened // context switching to Consumer's thread
Got: 2
Consumer called notify()
After get() n is: 2
Consumer ran: 3 times.
n: 2 // Consumer's thread ends here
Can someone help me understand why, in the above output, at line 2 the value of n
fetched by consumer is 1 when the producer already produced a new value which is 2 at line 1?有人能帮我理解为什么在上面的输出中,当生产者已经在第 1 行产生了一个新值 2 时,在第 2 行消费者获取的
n
的值为 1 吗? Since the same instance of Q2
are being shared by both the Producer's and Consumer's thread why is the changed value of n
not being reflected at line 2?由于
Q2
的同一个实例被生产者和消费者的线程共享,为什么n
的更改值没有反映在第 2 行? Also please clarify me the meaning of a threaded object even though I know what a thread is?即使我知道线程是什么,也请澄清线程对象的含义?
And if you don't see this behavior on running once the above code run a few times and you will see such behavior.而且,如果您在运行时没有看到这种行为,那么一旦上面的代码运行几次,您就会看到这种行为。
Your read from qn
in Consumer2::run
is racy, ie it is executed concurrently with the write to qn
in Q2::put
.您在
Consumer2::run
中从qn
读取的内容很活泼,即它与在Q2::put
中对qn
的写入同时执行。 As a result, it can read either the previous value or the currently written value of qn
.因此,它可以读取
qn
的先前值或当前写入的值。 A possible solution is move the printing of "Before get() n is..." to under the lock.一个可能的解决方案是将“Before get() n is...”的打印移动到锁下。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.