我目前正在學習 Java 中的多執行緒,在那里我了解了生產者-消費者問題,其中生產者正在生產,而消費者正在從佇列中消費,而與共享緩沖佇列上的生產者或消費者的數量無關。
在試圖解決這個問題時,出現了一個非常奇怪的問題。
Storage.java 的代碼:
class Storage{
int[] buffer;
int index;
final Object lock = new Object();
public Storage(int n){
buffer = new int[n];
Arrays.fill(buffer, -1);
index = 0;
}
public void addValueInBuffer(int value){
synchronized (lock) {
if (index >= buffer.length) {
System.out.println("Thread " Thread.currentThread().getName()
" producer need to wait" " with index " index);
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
System.out.println("Thread " Thread.currentThread().getName()
" is adding value " value " with index " index);
buffer[index] = value;
index ;
lock.notifyAll();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void consumeValueFromBuffer(){
synchronized (lock){
if(index <= 0){
System.out.println("Thread " Thread.currentThread().getName()
" consumer need to wait" " with index " index);
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
System.out.println("Thread " Thread.currentThread().getName()
" is consuming value " " with index " index);
index--;
buffer[index] = -1;
lock.notifyAll();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public int totalConsumption(){
int count = 0;
for (int i = 0; i < buffer.length; i ) {
if(buffer[i]==0){
count ;
}
}
return count;
}
}
Producer.java 的代碼
class Producer{
Storage storage;
public Producer(Storage storage){
this.storage = storage;
}
public void addValue(int value){
this.storage.addValueInBuffer(value);
}
}
Consumer.java 的代碼
class Consumer{
Storage storage;
public Consumer(Storage storage){
this.storage = storage;
}
private void consumeValue(){
this.storage.consumeValueFromBuffer();
}
}
ApplicationRunner.java 的代碼
public class ApplicationRunner {
public static void main(String[] args) throws InterruptedException {
int n = 1;
Storage storage = new Storage(n);
Producer producer = new Producer(storage);
Consumer consumer = new Consumer(storage);
Thread producerThread = new Thread(()-> {
for (int i = 0; i < 5; i ) {
producer.addValue(0);
}
});
Thread producerThread2 = new Thread(()-> {
for (int i = 0; i < 10; i ) {
producer.addValue(1);
}
});
Thread consumerThread = new Thread(consumer);
Thread consumerThread2 = new Thread(consumer);
producerThread.start();
producerThread2.start();
consumerThread.start();
consumerThread2.start();
producerThread.join();
producerThread2.join();
consumerThread.join();
consumerThread2.join();
System.out.println("Storage is " storage.totalConsumption() " which should be zero!");
}
}
共享緩沖佇列只有 1 個存盤空間,因此可以模擬特殊行為。兩個生產者總共生產 15 個資料,兩個消費者在無限回圈中消費。
上述程式的輸出是:
Thread Thread-0 is adding value 0 with index 0
Thread Thread-2 is consuming value with index 0
Thread Thread-1 is adding value 1 with index 0
Thread Thread-2 is consuming value with index 0
Thread Thread-0 is adding value 0 with index 0
Thread Thread-3 is consuming value with index 0
Thread Thread-0 is adding value 0 with index 0
Thread Thread-2 is consuming value with index 0
Thread Thread-1 is adding value 1 with index 0
Thread Thread-2 is consuming value with index 0
Thread Thread-0 is adding value 0 with index 0
Thread Thread-3 is consuming value with index 0
Thread Thread-0 is adding value 0 with index 0
Thread Thread-2 is consuming value with index 0
Thread Thread-1 is adding value 1 with index 0
Thread Thread-2 is consuming value with index 0
Thread Thread-3 consumer need to wait with index 0
Thread Thread-2 consumer need to wait with index 0
Thread Thread-1 is adding value 1 with index 0
Thread Thread-1 producer need to wait with index 1
Thread Thread-2 is consuming value with index 0
Thread Thread-3 consumer need to wait with index 0
Thread Thread-2 consumer need to wait with index 0
Thread Thread-1 is adding value 1 with index 0
Thread Thread-3 is consuming value with index 0
Thread Thread-1 is adding value 1 with index 0
Thread Thread-2 is consuming value with index 0
Thread Thread-1 is adding value 1 with index 0
Thread Thread-3 is consuming value with index 0
Thread Thread-1 is adding value 1 with index 0
Thread Thread-2 is consuming value with index 0
Thread Thread-1 is adding value 1 with index 0
Thread Thread-3 is consuming value with index 0
Thread Thread-2 consumer need to wait with index 0
Thread Thread-3 consumer need to wait with index 0
我預計總生產者將生產 15 件商品,消費者將消費 15 件商品。然而,情況并非如此,我觀察到生產者只生產 8 件商品,而消費者正在消費 8 件商品,我想這是因為 if-else 條件。
我不明白這種不尋常的行為,我在進行代碼同步或緩沖索引時是否遺漏了什么?
uj5u.com熱心網友回復:
不是一個完整的分析,但這一點至少在我看來是錯誤的:
synchronized (lock) {
if (index >= buffer.length) {
System.out.println("Thread " Thread.currentThread().getName()
" producer need to wait" " with index " index);
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
這里的問題是else. 如果緩沖區已滿,則等待,然后什么也不做。換句話說,因為緩沖區已滿,else塊將不會被執行,所以要添加的值永遠不會。
還有第二個錯誤:if (index >= buffer.length)不。如果有多個生產者,可能會喚醒一個添加值的執行緒,并且緩沖區可能仍然是滿的,因為另一個執行緒在您的執行緒之前添加了一個值。始終在回圈中測驗這樣的條件:while( index >= buffer.length ) lock.wait();這樣您就不會退出回圈,直到您需要繼續的條件為真。
未經測驗:
public void addValueInBuffer(int value) throws InterruptedException {
synchronized (lock) {
while(index >= buffer.length) lock.wait();
buffer[index] = value;
index ;
// you probably also need index = index % buffer.length
lock.notifyAll();
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/513749.html
標籤:爪哇多线程生产者-消费者
