System.out.print("进程"+temp[i]+"->");
}
System.out.print("进程"+temp[M-1]);
System.out.println("/n");
return0;
}
}
死锁示例
死锁问题是多线程特有的问题,它可以被认为是线程间切换消耗系统性能的一种极端情况。
在死锁时,线程间相互等待资源,而又不释放自身的资源,导致无穷无尽的等待,其结果是系统任务永远无法执行完成。
死锁问题是在多线程开发中应该坚决避免和杜绝的问题。
一般来说,要出现死锁问题需要满足以下条件:
1.互斥条件:
一个资源每次只能被一个线程使用。
2.请求与保持条件:
一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3.不剥夺条件:
进程已获得的资源,在未使用完之前,不能强行剥夺。
4.循环等待条件:
若干进程之间形成一种头尾相接的循环等待资源关系。
只要破坏死锁4个必要条件之一中的任何一个,死锁问题就能被解决。
我们先来看一个示例,前面说过,死锁是两个甚至多个线程被永久阻塞时的'一种运行局面,这种局面的生成伴随着至少两个线程和两个或者多个资源。
代码清单2所示的示例中,我们编写了一个简单的程序,它将会引起死锁发生,然后我们就会明白如何分析它。
清单2.死锁示例
publicclassThreadDeadlock{
publicstaticvoidmain(String[]args)throwsInterruptedException{
objectobj1=newobject();
objectobj2=newobject();
objectobj3=newobject();
Threadt1=newThread(newSyncThread(obj1,obj2),"t1");
Threadt2=newThread(newSyncThread(obj2,obj3),"t2");
Threadt3=newThread(newSyncThread(obj3,obj1),"t3");
t1.start();
Thread.sleep(5000);
t2.start();
Thread.sleep(5000);
t3.start();
}
}
classSyncThreadimplementsRunnable{
privateobjectobj1;
privateobjectobj2;
publicSyncThread(objecto1,objecto2){
this.obj1=o1;
this.obj2=o2;
}
@Override
publicvoidrun(){
Stringname=Thread.currentThread().getName();
System.out.println(name+"acquiringlockon"+obj1);
synchronized(obj1){
System.out.println(name+"acquiredlockon"+obj1);
work();
System.out.println(name+"acquiringlockon"+obj2);
synchronized(obj2){
System.out.println(name+"acquiredlockon"+obj2);
work();
}
System.out.println(name+"releasedlockon"+obj2);
}
System.out.println(name+"releasedlockon"+obj1);
System.out.println(name+"finishedexecution.");
}
privatevoidwork(){
try{
Thread.sleep(30000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
在上面的程序中同步线程正完成Runnable的接口,它工作的是两个对象,这两个对象向对方寻求死锁而且都在使用同步阻塞。
在主函数中,我使用了三个为同步线程运行的线程,而且在其中每个线程中都有一个可共享的资源。
这些线程以向第一个对象获取封锁这种方式运行。
但是当它试着向第二个对象获取封锁时,它就会进入等待状态,因为它已经被另一个线程封锁住了。
这样,在线程引起死锁的过程中,就形成了一个依赖于资源的循环。
当我执行上面的程序时,就产生了输出,但是程序却因为死锁无法停止。
输出如清单3所示。
清单3.清单2运行输出
t1acquiredlockonjava.lang.object@1dd3812
t2acquiringlockonjava.lang.object@c791b9
t2acquiredlockonjava.lang.object@c791b9
t3acquiringlockonjava.lang.object@1aa9f99
t3acquiredlockonjava.lang.object@1aa9f99
t1acquiringlockonjava.lang.object@c791b9
t2acquiringlockonjava.lang.object@1aa9f99
在此我们可以清楚地在输出结果中辨认出死锁局面,但是在我们实际所用的应用中,发现死锁并将它排除是非常难的。
死锁情况诊断
JVM提供了一些工具可以来帮助诊断死锁的发生,如下面程序清单4所示,我们实现了一个死锁,然后尝试通过jstack命令追踪、分析死锁发生。
清单4.死锁代码
importjava.util.concurrent.locks.ReentrantLock;
//下面演示一个简单的死锁,两个线程分别占用south锁和north锁,并同时请求对方占用的锁,导致死锁
publicclassDeadLockextendsThread{
protectedobjectmyDirect;
staticReentrantLocksouth=newReentrantLock();
staticReentrantLocknorth=newReentrantLock();
publicDeadLock(objectobj){
this.myDirect=obj;
if(myDirect==south){
this.setName("south");
}else{
this.setName("north");
}
}
@Override
publicvoidrun(){
if(myDirect==south){
try{
north.lockInterruptibly();//占用north
try{
Thread.sleep(500);
}catch(Exceptionex){
ex.printStackTrace();
}
south.lockInterruptibly();
System.out.println("cartosouthhaspassed");
}catch(InterruptedExceptionex){
System.out.println("cartosouthiskilled");
ex.printStackTrace();
}finally{
if(north.isHeldByCurrentThread()){
north.unlock();
}
if(south.isHeldByCurrentThread()){
south.unlock();
}
}
}
if(myDirect==north){
try{
south.lockInterruptibly();//占用south
try{
Thread.sleep(500);
}catch(Exceptionex){
ex.printStackTrace();
}
north.lockInterruptibly();
System.out.println("cartonorthhaspassed");
}catch(InterruptedExceptionex){
System.out.println("cartonorthiskilled");
ex.printStackTrace();
}finally{
if(north.isHeldByCurrentThread()){
north.unlock();
}
if(south.isHeldByCurrentThread()){
south.unlock();
}
}
}
}
publicstaticvoidmain(String[]args)throwsInterruptedException{
DeadLockcar2south=newDeadLock(south);
DeadLockcar2north=newDeadLock(north);
car2south.start();
car2north.start();
}
}
jstack可用于导出Java应用程序的线程堆栈,-l选项用于打印锁的附加信息。
我们运行jstack命令,输出入清单5和6所示,其中清单5里面可以看到线程处于运行状态,代码中调用了拥有锁投票、定时锁等候和可中断锁等候等特性的ReentrantLock锁机制。
清单6直接打印出出现死锁情况,报告north和sourth两个线程互相等待资源,出现了死锁。
清单5.jstack运行输出1
[root@facenode4~]#jstack-l31274
2015-01-2912:
40:
27
FullthreaddumpJavaHotSpot(TM)64-BitServerVM(20.45-b01mixedmode):
"AttachListener"daemonprio=10tid=0x00007f6d3c001000nid=
0x7a87waitingoncondition[0x0000000000000000]
java.lang.Thread.State:
RUNNABLE
Lockedownablesynchronizers:
-None
"DestroyJavaVM"prio=10tid=0x00007f6da4006800nid=
0x7a2bwaitingoncondition[0x0000000000000000]
java.lang.Thread.State:
RUNNABLE
Lockedownablesynchronizers:
-None
"north"prio=10tid=0x00007f6da4101800nid=
0x7a47waitingoncondition[0x00007f6d8963b000]
java.lang.Thread.State:
WAITING(parking)
atsun.misc.Unsafe.park(NativeMethod)
-parkingtowaitfor<0x000000075903c7c8>(
ajava.util.concurrent.locks.ReentrantLock$NonfairSync)
atjava.util.concurrent.locks.LockSupport.park(LockSupport.java:
156)
atjava.util.concurrent.locks.AbstractQueuedSynchronizer.
parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:
811)
atjava.util.concurrent.locks.AbstractQueuedSynchronizer.
doAcquireInterruptibly(AbstractQueuedSynchronizer.java:
867)
atjava.util.concurrent.locks.AbstractQueuedSynchronizer.
acquireInterruptibly(AbstractQueuedSynchronizer.java:
1201)
atjava.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:
312)
atDeadLock.run(DeadLock.java:
50)
Lockedownablesynchronizers:
-<0x000000075903c798>(ajava.util.concurrent.locks.ReentrantLock$NonfairSync)
"south"prio=10tid=0x00007f6da4100000nid=
0x7a46waitingoncondition[0x00007f6d8973c000]
java.lang.Thread.State:
WAITING(parking)
atsun.misc.Unsafe.park(NativeMethod)
-parkingtowaitfor<0x000000075903c798>(
ajava.util.concurrent.locks.ReentrantLock$NonfairSync)
atjava.util.concurrent.locks.LockSupport.park(LockSupport.java:
156)
atjava.util.concurrent.locks.AbstractQueuedSynchronizer.
parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:
811)
atjava.util.concurrent.locks.AbstractQueuedSynchronizer.
doAcquireInterruptibly(AbstractQueuedSynchronizer.java:
867)
atjava.util.concurrent.locks.AbstractQueuedSynchronizer.
acquireInterruptibly(AbstractQueuedSynchronizer.java:
1201)
atjava.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:
312)
atDeadLock.run(DeadLock.java:
28)
Lockedownablesynchronizers:
-<0x000000075903c7c8>(ajava.util.concurrent.locks.ReentrantLock$NonfairSync)
"LowMemoryDetector"daemonprio=10tid=0x00007f6da40d2800nid=
0x7a44runnable[0x0000000000000000]
java.lang.Thread.State:
RUNNABLE
Lockedownablesynchronizers:
-None
"C2CompilerThread1"daemonprio=10tid=0x00007f6da40d0000nid=
0x7a43waitingoncondition[0x0000000000000000]
java.lang.Thread.State:
RUNNABLE
Lockedownablesynchronizers:
-None
"C2CompilerThread0"daemonprio=10tid=0x00007f6da40cd000nid=
0x7a42waitingoncondition[0x0000000000000000]
java.lang.Thread.State:
RUNNABLE
Lockedownablesynchronizers:
-None
"SignalDispatcher"daemonprio=10tid=0x00007f6da40cb00