Java多线程程序陷入等待状态

时间:2019-07-17 12:40:55

标签: java multithreading synchronization

我开始用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 ?它至少应该检查对吗?

0 个答案:

没有答案