簡體   English   中英

Consumer Producer在Java中不起作用

[英]Consumer Producer doesn't work in java

我試圖根據正式的oracle示例( http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html )創建消費者生產者。

這種解決方案對我造成了一個問題,因為某種程度上消費(或生產)執行了兩次。

示例輸出:

0.27621192120612414

0.24838246527492802,0.30404137713732027

0.8848100139189661

0.9910138279470992,0.778606199890833

0.17368370874476935,0.5661899414440023 .......

我的代碼與oracle發布的代碼非常相似:

import java.util.Random;

public class Consumer implements Runnable {

    private SharedData sharedData;

    public Consumer(SharedData sharedData) {
    this.sharedData = sharedData;
    }

    @
    Override
    public void run() {
    // TODO Auto-generated method stub
    for (int i = 0; i < 10; i++) {

        double result = this.sharedData.calc();
        System.out.println(result);

        try {
        Thread.sleep(20);
        } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        }
    }
    }

public class Producer implements Runnable {

    private SharedData sharedData;

    private Random numGenerator = new Random();

    public Producer(SharedData sharedData) {
        this.sharedData = sharedData;
    }

    @
    Override
    public void run() {
        // TODO Auto-generated method stub
        for (int i = 0; i < 10; i++) {
        double firstNum = numGenerator.nextDouble();
        double secondNum = numGenerator.nextDouble();

        this.sharedData.store(firstNum, secondNum);
        System.out.println(firstNum + ", " + secondNum);

        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        }
    }
}

public class SharedData {

    private double x = 0;
    private double y = 0;

    private boolean empty = true;

    public synchronized double calc() {
        while (empty) {
        try {
            wait();
        } catch (InterruptedException e) {}
        }
        empty = true;
        notifyAll();
        return (x + y) / 2;
    }

    public synchronized void store(double x, double y) {
        while (!empty) {
        try {
            wait();
        } catch (InterruptedException e) {}
        }
        // Toggle status.
        empty = false;
        this.x = x;
        this.y = y;
        notifyAll();
    }
}

您的System.out.println調用不在任何同步部分中,因此,即使生產者在使用者消費之前就已經進行生產,也無法保證其輸出將在使用者輸出之前:

  1. 生產者線程產生,消費者線程等待
  2. 使用者線程消耗
  3. 使用者線程打印結果
  4. 生產者線程打印結果

System.out.println調用放在同步部分中,您應該看到消費者和生產者輸出之間有嚴格的區別。

您看到的問題不是防護系統故障,而是打印機制故障。

這是您可以使用的示例。 我創建了一個名為Calc的新類,其中包含計算時的詳細信息。 它顯示系統工作正常:

public class Consumer implements Runnable {

    private SharedData sharedData;

    public Consumer(SharedData sharedData) {
        this.sharedData = sharedData;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for (int i = 0; i < 10; i++) {

            Calc result = this.sharedData.calc();
            System.out.println(result);

            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}

public class Producer implements Runnable {

    private SharedData sharedData;

    private Random numGenerator = new Random();

    public Producer(SharedData sharedData) {
        this.sharedData = sharedData;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for (int i = 0; i < 10; i++) {
            double firstNum = numGenerator.nextDouble();
            double secondNum = numGenerator.nextDouble();

            this.sharedData.store(firstNum, secondNum);
            //System.out.println("Sum: " + firstNum + ", " + secondNum);

            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    }

}

public class Calc {

    final double x;
    final double y;
    final double r;

    public Calc(double x, double y, double r) {
        this.x = x;
        this.y = y;
        this.r = r;
    }

    public String toString() {
        return x + "," + y + "=" + r;
    }
}

public class SharedData {

    private double x = 0;
    private double y = 0;

    private volatile boolean empty = true;

    public synchronized Calc calc() {
        while (empty) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        // Create my Calc before the data can be changed.
        Calc calc = new Calc(x, y, (x + y) / 2);
        empty = true;
        notifyAll();
        return calc;
    }

    public synchronized void store(double x, double y) {
        while (!empty) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        // Toggle status.
        empty = false;
        this.x = x;
        this.y = y;
        notifyAll();
    }

}

public void test() throws InterruptedException {
    System.out.println("Hello");
    SharedData data = new SharedData();
    Thread pThread = new Thread(new Producer(data));
    Thread cThread = new Thread(new Consumer(data));
    pThread.start();
    cThread.start();
    pThread.join();
    cThread.join();
}

我得到:

0.6724169142503265,0.6079999474086301=0.6402084308294782
0.6821043385454105,0.08553214712777224=0.3838182428365914
0.9527912599940244,0.4659048372170267=0.7093480486055255
0.23726296551963733,0.09811671486141438=0.16768984019052585
0.192398049915115,0.7641124370868287=0.47825524350097187
0.014149497154971824,0.07331728450626529=0.04373339083061856
0.7143483172261206,0.532969217817149=0.6236587675216347
0.3660578187157878,0.5246494194965169=0.44535361910615234
0.8368831236536345,0.9004030373411539=0.8686430804973941
0.6986966105042433,0.4459182041312596=0.5723074073177514

據我所知,這加起來很好。

注意-但是,一旦在calc中將empty設置為true ,其他線程就可以修改xy 設置empty標志之前,您應該真正進行計算。

還要注意,您的empty標志應該是volatile

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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