为什么我会陷入僵局?
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();
}
}
}
我有一个多线程程序,它按 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();
}
}
}