假设我有以下代码,其中,一个线程产生平方和,而另一个线程打印它们把它们写到一个缓冲器:两个线程程序防止死锁
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