假設我有以下代碼,其中,一個線程產生平方和,而另一個線程打印它們把它們寫到一個緩衝器:兩個線程程序防止死鎖
import java.util.*;
public class Something {
public static Buffer buffer = new Buffer();
public static class Buffer {
private int[] buffer;
private static final int size = 10;
//Indexes for putting and taking element form buffer
private int in, out;
//Number of elements in buffer
private int k;
public Buffer() {
buffer = new int[size];
in = 0;
out = 0;
k = 0;
}
public synchronized void put(int e) {
try {
while (k == buffer.length) {
wait();
}
} catch (InterruptedException ex) {
}
buffer[in] = e;
k++;
in = ++in % size;
notifyAll();
}
public synchronized int take() {
try {
while (k == 0) {
wait();
}
} catch (InterruptedException ex) {
}
int e = buffer[out];
buffer[out] = 0;
out = ++out % size;
k--;
notifyAll();
return e;
}
public synchronized boolean notEmpty() {
return k != 0;
}
}
public static class Generator implements Runnable {
int limit;
public Generator(int lim) {
limit= lim;
}
@Override
public void run() {
for (int i = 1; i < limit; i++) {
buffer.put(i * i);
}
}
}
public static class Printer implements Runnable {
private Thread[] generators;
public Printer(Thread[] gen) {
generators = gen;
}
public synchronized boolean nobody() {
for (Thread th : generators) {
if (th.isAlive()) {
return false;
}
}
return true;
}
@Override
public void run() {
int x = 0;
while (!nobody() || buffer.notEmpty()) {
x = buffer.take();
System.out.println(x);
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread generator = new Thread(new Generator(69));
Thread printer = new Thread(new Printer(new Thread[]{generator}));
generator.start();
printer.start();
generator.join();
printer.join();
}
}
發生器應該產生的平方直到達到某個限制(在這種情況下,限制= 69)。打印機應打印由Generator生成的所有值。緩衝區有點像環形緩衝區。用於放置(在)和取(出)元素的索引在緩衝區大小的範圍內循環。緩衝區有從緩衝區中放入和取出元素的方法。發生器線程如果已滿(即,沒有零元素;爲了精確起見零元素爲0),它不能將元素放入緩衝區中。打印機以這種方式工作:首先檢查是否有活動的生成器線程,然後檢查緩衝區是否只包含零個元素。如果這兩個條件都不成立,則打印機線程終止。
現在,解決問題。我總是打印從1到68的所有方塊,這是該程序的預期輸出。 但是,在所有數字輸出後非常罕見的情況下,我得到了一個僵局。多少次?那麼,也許在100個程序執行中有1個。我不得不繼續在NetBeans上點擊「F6」,以免陷入僵局。是的,我知道我可以測試這個只需將所有主代碼放入for循環。 相反,如果我在打印機的運行方法中註釋掉打印行,幾乎總是發生死鎖。在這裏:
@Override
public void run() {
int x = 0;
while (!nobody() || buffer.notEmpty()) {
x = buffer.take();
//System.out.println(x);
}
}
我不希望這種行爲,因爲元素仍然會從緩衝和發電機所應被喚醒。
爲什麼會發生這種情況?我該如何解決它? 很抱歉,如果問題不夠清楚,我會盡可能地澄清它,如果需要的話。
您可以確定哪個線程卡住(第一個)? – Turing85
我確定它是打印機。它永遠在等待Generator將一些元素放入緩衝區。 – Schizo
這個程序看起來非常複雜,它應該更復雜。爲什麼不使用隊列並刪除所有同步的塊。 – Leon