![](/img/trans.png)
[英]Consumer doesn't work in my simple producer/consumer/queue code in 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
調用不在任何同步部分中,因此,即使生產者在使用者消費之前就已經進行生產,也無法保證其輸出將在使用者輸出之前:
將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
,其他線程就可以修改x
和y
。 設置empty
標志之前,您應該真正進行計算。
還要注意,您的empty
標志應該是volatile
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.