详解Java的线程的优先级以及死锁
Java线程优先级
需要避免的与多任务处理有关的特殊错误类型是死锁(deadlock)。死锁发生在当两个线程对一对同步对象有循环依赖关系时。例如,假定一个线程进入了对象X的管程而另一个线程进入了对象Y的管程。如果X的线程试图调用Y的同步方法,它将像预料的一样被锁定。而Y的线程同样希望调用X的一些同步方法,线程永远等待,因为为到达X,必须释放自己的Y的锁定以使第一个线程可以完成。死锁是很难调试的错误,因为:
通常,它极少发生,只有到两线程的时间段刚好符合时才能发生。
它可能包含多于两个的线程和同步对象(也就是说,死锁在比刚讲述的例子有更多复杂的事件序列的时候可以发生)。
为充分理解死锁,观察它的行为是很有用的。下面的例子生成了两个类,A和B,分别有foo()和bar()方法。这两种方法在调用其他类的方法前有一个短暂的停顿。主类,名为Deadlock,创建了A和B的实例,然后启动第二个线程去设置死锁环境。foo()和bar()方法使用sleep()强迫死锁现象发生。
//Anexampleofdeadlock.
classA{
synchronizedvoidfoo(Bb){
Stringname=Thread.currentThread().getName();
System.out.println(name+"enteredA.foo");
try{
Thread.sleep(1000);
}catch(Exceptione){
System.out.println("AInterrupted");
}
System.out.println(name+"tryingtocallB.last()");
b.last();
}
synchronizedvoidlast(){
System.out.println("InsideA.last");
}
}
classB{
synchronizedvoidbar(Aa){
Stringname=Thread.currentThread().getName();
System.out.println(name+"enteredB.bar");
try{
Thread.sleep(1000);
}catch(Exceptione){
System.out.println("BInterrupted");
}
System.out.println(name+"tryingtocallA.last()");
a.last();
}
synchronizedvoidlast(){
System.out.println("InsideA.last");
}
}
classDeadlockimplementsRunnable{
Aa=newA();
Bb=newB();
Deadlock(){
Thread.currentThread().setName("MainThread");
Threadt=newThread(this,"RacingThread");
t.start();
a.foo(b);//getlockonainthisthread.
System.out.println("Backinmainthread");
}
publicvoidrun(){
b.bar(a);//getlockonbinotherthread.
System.out.println("Backinotherthread");
}
publicstaticvoidmain(Stringargs[]){
newDeadlock();
}
}
运行程序后,输出如下:
MainThreadenteredA.foo RacingThreadenteredB.bar MainThreadtryingtocallB.last() RacingThreadtryingtocallA.last()
因为程序死锁,你需要按CTRL-C来结束程序。在PC机上按CTRL-BREAK(或在Solaris下按CTRL-\)你可以看到全线程和管程缓冲堆。你会看到RacingThread在等待管程a时占用管程b,同时,MainThread占用a等待b。该程序永远都不会结束。像该例阐明的,你的多线程程序经常被锁定,死锁是你首先应检查的问题。
Java线程死锁
需要避免的与多任务处理有关的特殊错误类型是死锁(deadlock)。死锁发生在当两个线程对一对同步对象有循环依赖关系时。例如,假定一个线程进入了对象X的管程而另一个线程进入了对象Y的管程。如果X的线程试图调用Y的同步方法,它将像预料的一样被锁定。而Y的线程同样希望调用X的一些同步方法,线程永远等待,因为为到达X,必须释放自己的Y的锁定以使第一个线程可以完成。死锁是很难调试的错误,因为:
通常,它极少发生,只有到两线程的时间段刚好符合时才能发生。
它可能包含多于两个的线程和同步对象(也就是说,死锁在比刚讲述的例子有更多复杂的事件序列的时候可以发生)。
为充分理解死锁,观察它的行为是很有用的。下面的例子生成了两个类,A和B,分别有foo()和bar()方法。这两种方法在调用其他类的方法前有一个短暂的停顿。主类,名为Deadlock,创建了A和B的实例,然后启动第二个线程去设置死锁环境。foo()和bar()方法使用sleep()强迫死锁现象发生。
//Anexampleofdeadlock.
classA{
synchronizedvoidfoo(Bb){
Stringname=Thread.currentThread().getName();
System.out.println(name+"enteredA.foo");
try{
Thread.sleep(1000);
}catch(Exceptione){
System.out.println("AInterrupted");
}
System.out.println(name+"tryingtocallB.last()");
b.last();
}
synchronizedvoidlast(){
System.out.println("InsideA.last");
}
}
classB{
synchronizedvoidbar(Aa){
Stringname=Thread.currentThread().getName();
System.out.println(name+"enteredB.bar");
try{
Thread.sleep(1000);
}catch(Exceptione){
System.out.println("BInterrupted");
}
System.out.println(name+"tryingtocallA.last()");
a.last();
}
synchronizedvoidlast(){
System.out.println("InsideA.last");
}
}
classDeadlockimplementsRunnable{
Aa=newA();
Bb=newB();
Deadlock(){
Thread.currentThread().setName("MainThread");
Threadt=newThread(this,"RacingThread");
t.start();
a.foo(b);//getlockonainthisthread.
System.out.println("Backinmainthread");
}
publicvoidrun(){
b.bar(a);//getlockonbinotherthread.
System.out.println("Backinotherthread");
}
publicstaticvoidmain(Stringargs[]){
newDeadlock();
}
}
运行程序后,输出如下:
MainThreadenteredA.foo RacingThreadenteredB.bar MainThreadtryingtocallB.last() RacingThreadtryingtocallA.last()
因为程序死锁,你需要按CTRL-C来结束程序。在PC机上按CTRL-BREAK(或在Solaris下按CTRL-\)你可以看到全线程和管程缓冲堆。你会看到RacingThread在等待管程a时占用管程b,同时,MainThread占用a等待b。该程序永远都不会结束。像该例阐明的,你的多线程程序经常被锁定,死锁是你首先应检查的问题。