簡體   English   中英

為什么有時在生產者-消費者問題的輸出中,消費者得到的是以前的值,而不是生產者產生的新值?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM