我从java documentation学习线程同步。我实施了一个着名的问题生产者 - 消费者问题。但它没有按预期给出结果。我在HERE,HERE,HERE,HERE,HERE以及其他一些堆栈交换中搜索了很多关于此问题的信息。堆栈交换站点,但无法解决我的问题。这是我的代码:
GetSetItem.java
public class GetSetItem {
private volatile boolean available = false;
private int item;
public synchronized void set(int item) {
while(available) {
try {
wait();
} catch (InterruptedException ie) {
System.err.println("Interrupted: " + ie.getMessage());
}
}
this.item = item;
available = true;
notifyAll();
}
public synchronized int get() {
while(!available) {
try {
wait();
} catch (InterruptedException ie) {
System.err.println("Interrupted: " + ie.getMessage());
}
}
available = false;
notifyAll();
return item;
}
}
Consumer.java
public class Consumer implements Runnable {
private int number; // Just for show #1,#2 etc. For future use
private GetSetItem consumer;
public Consumer(GetSetItem item, int seq) {
consumer = item;
number = seq;
}
@Override
public void run() {
int value = -1;
for(int i = 0; i < 10; i++) {
value = consumer.get();
System.out.println("Consumer #" + number + " get: " + value);
}
}
}
Producer.java
public class Producer implements Runnable {
private GetSetItem producer;
private int number = 0;
public Producer(GetSetItem item, int seq) {
producer = item;
number = seq;
}
@Override
public void run() {
for(int i = 0; i < 10; i++) {
producer.set(i);
System.out.println("Producer #" + number + " Put: " + i);
}
}
}
ProducerConsumerMain.java
public class ProducerConsumerMain {
public static void main(String[] args) {
GetSetItem item = new GetSetItem();
Producer p = new Producer(item, 1);
Consumer c = new Consumer(item, 1);
new Thread(p).start();
new Thread(c).start();
}
}
输出为:
Consumer #1 get: 0
Producer #1 Put: 0
Producer #1 Put: 1
Consumer #1 get: 1
Producer #1 Put: 2
Consumer #1 get: 2
Producer #1 Put: 3
Consumer #1 get: 3
Producer #1 Put: 4
Producer #1 Put: 5
Consumer #1 get: 4
Consumer #1 get: 5
Producer #1 Put: 6
Producer #1 Put: 7
Consumer #1 get: 6
Consumer #1 get: 7
Consumer #1 get: 8
Producer #1 Put: 8
Producer #1 Put: 9
Consumer #1 get: 9
但输出应该在生产者中 - &gt;消费者格式。这意味着消费者只有在生产者可用和生产的情况下才能消费。我还尝试了private boolean available = false
而不是private volatile boolean available = false;
,但没有收到预期的输出。
所以请告诉我我做了什么错,怎样才能成功实现这个问题。
答案 0 :(得分:1)
您的代码似乎很好,问题很可能是System.out
不是线程安全的。您还需要同步println()
来电:
@Override
public void run() {
for (int i = 0; i < 10; i++) {
producer.set(i);
synchronized (System.out) {
System.out.println("Producer #" + number + " Put: " + i);
}
}
}
然后,输出将类似于:
Producer #1 Put: 0
Producer #1 Put: 1
Consumer #1 get: 0
Consumer #1 get: 1
Producer #1 Put: 2
Producer #1 Put: 3
Consumer #1 get: 2
Consumer #1 get: 3
Producer #1 Put: 4
Consumer #1 get: 4
Producer #1 Put: 5
Producer #1 Put: 6
Consumer #1 get: 5
Consumer #1 get: 6
Consumer #1 get: 7 <<<<
Producer #1 Put: 7 <<<<
Producer #1 Put: 8
Consumer #1 get: 8
Consumer #1 get: 9 <<<<
Producer #1 Put: 9 <<<<
您的帖子仍然可以在get/set
和println
语句之间暂停,在这种情况下,看起来好像您的消费者正在消费尚未生成的内容,例如我指示的位置在上面的输出中。但这只是一个输出问题,你的代码运行正常并完成它应该做的事情。
答案 1 :(得分:1)
我在System.out.println(...)
类的get()
和set()
方法中使用GetSetItem
语句,并从相应的System.out.println(...)
中移除producer
,从而解决了问题和consumer
课程。正如:
GetSetItem.java的 get()方法
public synchronized void set(int item, int number) {
while(available) {
try {
wait();
} catch (InterruptedException ie) {
System.err.println("Interrupted: " + ie.getMessage());
}
}
this.item = item;
/* Putting this line here gives expected output because this
* statement is synchronized due to method synchronization.
*/
System.out.println("Producer #" + number + " Produced: " + item);
available = true;
notifyAll();
}
GetSetItem.java的set()方法
public synchronized int get(int number) {
while (!available) {
try {
wait();
} catch (InterruptedException ie) {
System.err.println("Interrupted: " + ie.getMessage());
}
}
/*
* Putting this line here gives expected output because this statement
* is synchronized due to method synchronization.
*/
System.out.println("Consumer #" + number + " Consumed: " + item);
available = false;
notifyAll();
return item;
}
编辑:输出:
Producer #1 Produced: 0
Consumer #1 Consumed: 0
Producer #1 Produced: 1
Consumer #1 Consumed: 1
Producer #1 Produced: 2
Consumer #1 Consumed: 2
Producer #1 Produced: 3
Consumer #1 Consumed: 3
Producer #1 Produced: 4
Consumer #1 Consumed: 4
Producer #1 Produced: 5
Consumer #1 Consumed: 5
Producer #1 Produced: 6
Consumer #1 Consumed: 6
Producer #1 Produced: 7
Consumer #1 Consumed: 7
Producer #1 Produced: 8
Consumer #1 Consumed: 8
Producer #1 Produced: 9
Consumer #1 Consumed: 9