为什么我会陷入僵局?

Why do I get a deadlock?

我有一个多线程程序,它按 strs 次的顺序对线程进行排序。每个线程都有自己的监视器。该线程的一个监视器 (lock) 和下一个线程的另一个监视器 (unlock) 被传递给每个线程的构造函数。首先,每个线程启动时,必须在array[0] != this时停止,但是如果在我第13行这样写,就会出现死锁。所以我使用 Threads.count,它在每次迭代时递增。这样程序就可以工作了。你能告诉我为什么会这样吗?

class Foo extends Thread
{
    private Object lock, unlock;
    Foo(Object lock, Object unlock)
    {
        this.lock = lock;
        this.unlock = unlock;
    }
    public void run()
    {
        synchronized(lock)
        {
            if(Threads.array[Threads.count] != this)    // line 13!!!
            {
                waiter();
            }
            for(int i = 0; i < Threads.strs; ++i)
            {
                if(Threads.array[0] == this)
                {
                    System.out.println(i+1);
                }
                System.out.print(getName() + ' ');
                ++Threads.count;
                if(Threads.array[Threads.thrs-1] == this)
                {
                    System.out.println();
                }
                if(unlock != lock)
                {
                    synchronized(unlock)
                    {
                        unlock.notify();
                    }
                    waiter();
                }
            }
        }
    }
    void waiter()
    {
        try
        {
            lock.wait();
        }
        catch(InterruptedException e)
        {
            e.printStackTrace();
            System.exit(1);
        }
    }
}

public class Threads
{
    public static Thread array[];
    public static Object lock[];
    public static int count, strs, thrs;
    public static void main(String args[])
    {
        thrs = 0;
        strs = 0;
        count = 0;
        try
        {
            assert(args.length == 2);
            thrs = Integer.parseInt(args[0]);
            strs = Integer.parseInt(args[1]);
            assert((thrs > 0) && (strs > 0));
        }
        catch(NumberFormatException | AssertionError e)
        {
            System.out.println("Uncorrect enter!");
            System.exit(1);
        }
        lock = new Object[thrs];
        array = new Thread[thrs];
        for(int i = 0; i < thrs; ++i)
        {
            lock[i] = new Object();
        }
        for(int i = 0; i < thrs; ++i)
        {
            if(i != thrs-1)
            {
                array[i] = new Foo(lock[i],lock[i+1]);
            }else
            {
                array[i] = new Foo(lock[i],lock[0]);
            }
            array[i].start();
        }
    }
}

第 13 行基本上说 "wait to get notified by a preceding thread, unless I am the first thread"。这是有道理的:从我从代码中可以看出,您希望线程按照您创建线程的顺序一个接一个地执行任务(这违背了使用线程的目的,但这是另一回事) .
另请注意,程序不会退出,因为所有线程都在循环结束时调用 waiter()

所以解决方案有点简单:让所有线程在循环开始时等待,但在创建所有线程后,触发第一个线程启动 运行(这将触发其他线程开始 运行)。下面是您的代码的略微调整副本,其中包含我提到的两个更改:

class ThreadsInSequence extends Thread
{
    private Object lock, unlock;
    ThreadsInSequence(Object lock, Object unlock)
    {
        this.lock = lock;
        this.unlock = unlock;
    }
    public void run()
    {
        synchronized(lock)
        {
            for(int i = 0; i < strs; ++i)
            {
                waiter();
                if(array[0] == this)
                {
                    System.out.println(i+1);
                }
                System.out.print(getName() + ' ');
                ++count;
                if(array[thrs-1] == this)
                {
                    System.out.println();
                }
                if(unlock != lock)
                {
                    synchronized(unlock)
                    {
                        unlock.notify();
                    }
                }
            }
        }
    }
    void waiter()
    {
        try
        {
            lock.wait();
        }
        catch(InterruptedException e)
        {
            e.printStackTrace();
            System.exit(1);
        }
    }

    public static Thread array[];
    public static Object locks[];
    public static int count, strs, thrs;
    public static void main(String args[])
    {
        thrs = 3;
        strs = 6;
        count = 0;
        locks = new Object[thrs];
        array = new Thread[thrs];
        for(int i = 0; i < thrs; ++i)
        {
            locks[i] = new Object();
        }
        for(int i = 0; i < thrs; ++i)
        {
            if(i != thrs-1)
            {
                array[i] = new ThreadsInSequence(locks[i],locks[i+1]);
            }else
            {
                array[i] = new ThreadsInSequence(locks[i],locks[0]);
            }
            array[i].start();
        }
        synchronized(locks[0]) {
            locks[0].notify();
        }
    }
}