我试图根据官方的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();
}
}
答案 0 :(得分:1)
您的System.out.println
次呼叫不在任何同步部分中,因此即使生产者在消费者消费之前已经生产,也不能保证其输出将在消费者输出之前出现:
将System.out.println
调用放在同步部分中,您应该看到消费者和生产者输出之间存在严格的交替。
答案 1 :(得分:0)
您所看到的问题不是保护系统的故障,而是您的打印机制失败。
以下是您可以使用的示例。我创建了一个名为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
就我所见,这很好。
注意 - 然而 - 一旦您在empty
中将true
设置为calc
,其他线程就可以修改x
和y
。您应该在设置empty
标志之前 之前进行计算。
另请注意,您的empty
标记应为volatile
。