为什么我会遇到僵局?

时间:2015-03-21 13:59:28

标签: java multithreading 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();
        }
    }
}

1 个答案:

答案 0 :(得分:0)

第13行基本上说“等待前一个线程通知,除非我是第一个线程”。这是有道理的:从我从代码中可以看出,你希望线程按照你创建线程的顺序逐个完成它们的任务(哪种方式违背了使用线程的目的,但这是另一个故事) 。
另请注意,程序不会退出,因为所有线程都在循环结束时调用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();
        }
    }
}