我开始用Java编写多线程程序,但是这个特定程序遇到了问题,即使看起来好像不应该,它似乎也无限期地处于等待状态。< / p>
在此程序中,有一些线程在不同的容器之间分配数字(令牌):每个线程都有一个容器数组,从中获取数字(每个容器取一个数字),以及一个容器数组。放进去。
从代码中可以看到,我确保在获取数字之前,线程确保每个Container都有准备好获取的数字,以避免无限等待。
我尝试了以下结构的程序:4个线程和4个容器,线程1和2都从容器1和2中获取数字,并将它们都放入容器3中。 线程3从容器3取出数字并将其放入容器4和1,线程4从容器4取出数字并将其放入容器2。 如前所述,前两个容器使用一个数字初始化,另外两个没有数字初始化。
public class Main {
public static void main(String[] args) throws InterruptedException{
Container[] c = new Container[4];
ThreadT[] threads = new ThreadT[4];
c[0] = new Container(1,1);
c[1] = new Container(1,2);
c[2] = new Container(0,3);
c[3] = new Container(0,4);
threads[0]= new ThreadT(0, 200, new Container[]{c[0],c[1]}, new Container[]{c[2]}, c);
threads[1]= new ThreadT(100, 200, new Container[]{c[0],c[1]}, new Container[]{c[2]}, c);
threads[2]= new ThreadT(500, 600, new Container[]{c[2]}, new Container[]{c[0], c[3]}, c);
threads[3]= new ThreadT(200, 300, new Container[]{c[3]}, new Container[]{c[1]}, c);
for(ThreadT t : threads) t.start();
Thread.sleep(30000);
for(ThreadT t : threads) t.interrupt();
}
}
程序运行一段时间:前两个线程之一获取数字并将其毫无问题地转移到容器3中,但是一旦数字进入容器3中,程序就没有明显的原因停止:线程3应该通过allTokensAvailable()
函数中的transferMessages()
检查并从容器中获取一个数字,但是没有。
我尝试移动一些wait()条件,并尝试了不同的条件,但均未成功。 每次更改它们时,我都会打印所有容器的状态以进行调试。
class Container{
private int id;
private Random r = new Random();
private ArrayList<Integer> tokens = new ArrayList();
public Container(int tokensToGenerate, int id){
this.id = id;
for(int i = 0; i < tokensToGenerate; i++){
tokens.add(r.nextInt(10));
}
}
public synchronized void putToken(int token){
tokens.add(token);
notifyAll();
}
public synchronized int getToken() throws InterruptedException {
while(tokens.isEmpty()) wait();
int result = tokens.get(0);
tokens.remove(0);
return result;
}
public void printStatus(){
System.out.println("Container "+id+" has "+tokens.size()+" elements");
}
public synchronized boolean hasTokens(){
return !tokens.isEmpty();
}
}
class ThreadT extends Thread{
private Container[] takeFrom;
private Container[] sendTo;
private Container[] allContainers;
private ArrayList<Integer> tokensToSend = new ArrayList();
private Random r = new Random();
private int minWait;
private int maxWait;
public ThreadT(int min, int max, Container[] senders, Container[] receivers, Container[] all){
takeFrom = senders;
sendTo = receivers;
allContainers = all;
minWait = min;
maxWait = max;
}
private boolean allTokensAvailable(){
boolean result = true;
for(Container c : takeFrom){
if(!c.hasTokens()) result = false;
}
System.out.println("allTokensAvailable for "+Thread.currentThread().getName()+" "+result);
return result;
}
private void printAllStatus(){
for(Container c : allContainers) c.printStatus();
}
private void transferMessages() throws InterruptedException{
while(!allTokensAvailable()) {
System.out.println(Thread.currentThread().getName()+" waiting");
wait();
}
for (Container c : takeFrom){
tokensToSend.add(c.getToken());
System.out.println(Thread.currentThread().getName()+" is receiving messages");
printAllStatus();
}
sleep((r.nextInt(maxWait-minWait)+minWait));
for(Container c : sendTo){
for(int i : tokensToSend){
System.out.println(Thread.currentThread().getName()+" is sending messages");
c.putToken(i);
printAllStatus();
}
}
tokensToSend.clear();
}
@Override
public synchronized void run(){
try{
while(true){
transferMessages();
}
} catch (InterruptedException e) {}
}
}
理论上,线程3应该从容器3中获取一个数字,并将该数字的副本放入容器1和4中。
编辑:我投入了很多打印语句来弄清楚线程的运行情况,而且似乎存在一个问题,即使我放notifyAll()
而不是{,线程也无法执行检查{1}}。
这是程序的输出:
notify
为什么当容器3收到一个元素时,线程3甚至没有尝试检查? (没有allTokensAvailable for Thread-2 false
allTokensAvailable for Thread-0 true
allTokensAvailable for Thread-1 true
allTokensAvailable for Thread-3 false
Thread-0 is receiving messages
Thread-3 waiting
Thread-2 waiting
Container 1 has 0 elements
Container 2 has 1 elements
Container 3 has 0 elements
Container 4 has 0 elements
Thread-0 is receiving messages
Container 1 has 0 elements
Container 2 has 0 elements
Container 3 has 0 elements
Container 4 has 0 elements
Thread-0 is sending messages
Container 1 has 0 elements
Container 2 has 0 elements
Container 3 has 1 elements
Container 4 has 0 elements
Thread-0 is sending messages
Container 1 has 0 elements
Container 2 has 0 elements
Container 3 has 2 elements
Container 4 has 0 elements
allTokensAvailable for Thread-0 false
Thread-0 waiting
?它至少应该检查对吗?