[英]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?
我有下面的 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);
}
}
一個特定的輸出:
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
有人能幫我理解為什么在上面的輸出中,當生產者已經在第 1 行產生了一個新值 2 時,在第 2 行消費者獲取的n
的值為 1 嗎? 由於Q2
的同一個實例被生產者和消費者的線程共享,為什么n
的更改值沒有反映在第 2 行? 即使我知道線程是什么,也請澄清線程對象的含義?
而且,如果您在運行時沒有看到這種行為,那么一旦上面的代碼運行幾次,您就會看到這種行為。
您在Consumer2::run
中從qn
讀取的內容很活潑,即它與在Q2::put
中對qn
的寫入同時執行。 因此,它可以讀取qn
的先前值或當前寫入的值。 一個可能的解決方案是將“Before get() n is...”的打印移動到鎖下。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.