Java多執行緒中避免在多生產者和多消費者場景中出現假死
阿新 • • 發佈:2019-01-11
在多執行緒程式設計中,如果所有執行緒全部都經由wait()方法進入等待狀態,那麼程式就進入了假死狀態
程式示例
考慮這個例子,來自《Java多執行緒程式設計核心技術》:
生產者類P:
//生產者
public class P {
private String lock;
public P(String lock) {
super();
this.lock = lock;
}
public void setValue() {
try {
synchronized (lock) {
while (!ValueObject. value.equals("")) {
System.out.println("生產者 "
+ Thread.currentThread().getName() + " WAITING了★");
lock.wait();
}
System.out.println("生產者 " + Thread.currentThread().getName()
+ " RUNNABLE了");
String value = System.currentTimeMillis() + "_"
+ System.nanoTime();
ValueObject.value = value;
lock.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
消費者類C:
//消費者
public class C {
private String lock;
public C(String lock) {
super();
this.lock = lock;
}
public void getValue() {
try {
synchronized (lock) {
while (ValueObject.value.equals("")) {
System.out.println("消費者 "
+ Thread.currentThread().getName() + " WAITING了☆");
lock.wait();
}
System.out.println("消費者 " + Thread.currentThread().getName()
+ " RUNNABLE了");
ValueObject.value = "";
lock.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ValueObject類:
public class ValueObject {
public static String value = "";
}
作為主類的Run類:
public class Run {
public static void main(String[] args) throws InterruptedException {
String lock = "";
P p = new P(lock);
C r = new C(lock);
Thread[] pThread = new Thread[2];
Thread[] rThread = new Thread[2];
for (int i = 0; i < 2; i++) {
pThread[i] = new Thread(()->{
while(true){
p.setValue();
}
});
pThread[i].setName("生產者" + (i + 1));
rThread[i] = new Thread(()->{
while(true){
r.getValue();
}
});
rThread[i].setName("消費者" + (i + 1));
pThread[i].start();
rThread[i].start();
}
Thread.sleep(5000);
Thread[] threadArray = new Thread[Thread.currentThread()
.getThreadGroup().activeCount()];
Thread.currentThread().getThreadGroup().enumerate(threadArray);
for (int i = 0; i < threadArray.length; i++) {
System.out.println(threadArray[i].getName() + " "
+ threadArray[i].getState());
}
}
}
執行程式可能出現的一種情況是:
生產者 生產者1 RUNNABLE了
生產者 生產者1 WAITING了★
生產者 生產者2 WAITING了★
消費者 消費者2 RUNNABLE了
消費者 消費者2 WAITING了☆
消費者 消費者1 WAITING了☆
生產者 生產者1 RUNNABLE了
生產者 生產者1 WAITING了★
生產者 生產者2 WAITING了★
main RUNNABLE
生產者1 WAITING
消費者1 WAITING
生產者2 WAITING
消費者2 WAITING
可以看到,最後所有執行緒都處於等待狀態,程式最後也就呈現了“假死”狀態,不能夠繼續執行下去。
儘管已經使用了notify/wait進行執行緒之間的通訊,但是仍然出現假死現象,究其原因是因為連續喚醒同類執行緒。
在多生產者多消費者的場景中,產生了“生產者”喚醒“生產者”或者“消費者”喚醒“消費者”的現象。如果這樣的情況越來越多,最終就會導致假死。
解決方法
解決假死問題可以通過簡單的使用notifyAll()方法的呼叫來解決即可。
這樣就可以有效確保每次喚醒的執行緒並非只有同類執行緒。