Java程序死锁问题原理及解决方案Word文件下载.docx
《Java程序死锁问题原理及解决方案Word文件下载.docx》由会员分享,可在线阅读,更多相关《Java程序死锁问题原理及解决方案Word文件下载.docx(21页珍藏版)》请在冰豆网上搜索。
![Java程序死锁问题原理及解决方案Word文件下载.docx](https://file1.bdocx.com/fileroot1/2023-2/2/b35b287f-5ee3-4ff6-89f4-9d968f64f4f5/b35b287f-5ee3-4ff6-89f4-9d968f64f4f51.gif)
//每个进程还需要的资源数
publicstaticintNEED[][]={{7,5,3},{3,2,2},{9,0,2},
//每次申请的资源数
publicstaticintRequest[]={0,0,0};
//进程数与资源数
publicstaticintM=5,N=3;
intFALSE=0;
intTRUE=1;
publicvoidshowdata(){
inti,j;
System.out.print("
系统可用的资源数为:
/n"
);
for(j=0;
j<
N;
j++){
资源"
+j+"
:
"
+AVAILABLE[j]+"
}
System.out.println();
System.out.println("
各进程还需要的资源量:
for(i=0;
i<
M;
i++){
进程"
+i+"
+NEED[i][j]+"
各进程已经得到的资源量:
System.out.print(i);
+ALLOCATION[i][j]+"
//分配资源,并重新更新各种状态
publicvoidchangdata(intk){
intj;
AVAILABLE[j]=AVAILABLE[j]-Request[j];
ALLOCATION[k][j]=ALLOCATION[k][j]+Request[j];
NEED[k][j]=NEED[k][j]-Request[j];
};
//回收资源,并重新更新各种状态
publicvoidrstordata(intk){
AVAILABLE[j]=AVAILABLE[j]+Request[j];
ALLOCATION[k][j]=ALLOCATION[k][j]-Request[j];
NEED[k][j]=NEED[k][j]+Request[j];
//释放资源
publicvoidfree(intk){
for(intj=0;
AVAILABLE[j]=AVAILABLE[j]+ALLOCATION[k][j];
释放"
+k+"
号进程的"
资源!
publicintcheck0(intk){
intj,n=0;
if(NEED[k][j]==0)
n++;
if(n==3)
return1;
else
return0;
//检查安全性函数
//所以银行家算法其核心是:
保证银行家系统的资源数至少不小于一个客户的所需要的资源数。
在安全性检查函数chkerr()上由这个方法来实现
//这个循环来进行核心判断,从而完成了银行家算法的安全性检查工作。
publicintchkerr(ints){
intWORK;
intFINISH[]=newint[M],temp[]=newint[M];
//保存临时的安全进程序列
inti,j,k=0;
i++)
FINISH[i]=FALSE;
WORK=AVAILABLE[j];
//第j个资源可用数
i=s;
//判断第i个进程是否满足条件
while(i<
M){
if(FINISH[i]==FALSE&
&
NEED[i][j]<
=WORK){
WORK=WORK+ALLOCATION[i][j];
FINISH[i]=TRUE;
temp[k]=i;
k++;
i=0;
}else{
i++;
if(FINISH[i]==FALSE){
/n系统不安全!
!
本次资源申请不成功!
/n经安全性检查,系统安全,本次分配成功。
本次安全序列:
M-1;
+temp[i]+"
->
+temp[M-1]);
死锁示例
死锁问题是多线程特有的问题,它可以被认为是线程间切换消耗系统性能的一种极端情况。
在死锁时,线程间相互等待资源,而又不释放自身的资源,导致无穷无尽的等待,其结果是系统任务永远无法执行完成。
死锁问题是在多线程开发中应该坚决避免和杜绝的问题。
一般来说,要出现死锁问题需要满足以下条件:
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();
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){
acquiredlockon"
work();
+obj2);
synchronized(obj2){
releasedlockon"
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"
north"
north.lockInterruptibly();
//占用north
Thread.sleep(500);
}catch(Exceptionex){
ex.printStackTrace();
south.lockInterruptibly();
cartosouthhaspassed"
}catch(InterruptedExceptionex){
cartosouthiskilled"
}finally{
if(north.isHeldByCurrentThread()){
north.unlock();
if(south.isHeldByCurrentThread()){
south.unlock();
if(myDirect==north){
//占用south
cartonorthhaspassed"
cartonorthiskilled"
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]
prio=10tid=0x00007f6da4101800nid=
0x7a47waitingoncondition[0x00007f6d8963b000]
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)
doAcquireInterruptibly(AbstractQueuedSynchronizer.java:
867)
acquireInterruptibly(AbstractQueuedSynchronizer.java:
1201)
atjava.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:
312)
atDeadLock.run(DeadLock.java:
50)
-<
0x000000075903c798>
(ajava.util.concurrent.locks.ReentrantLock$NonfairSync)
prio=10tid=0x00007f6da4100000nid=
0x7a46waitingoncondition[0x00007f6d8973c000]
28)
LowMemoryDetector"
daemonprio=10tid=0x00007f6da40d2800nid=
0x7a44runnable[0x0000000000000000]
C2CompilerThread1"
daemonprio=10tid=0x00007f6da40d0000nid=
0x7a43waitingoncondition[0x0000000000000000]
C2CompilerThread0"
daemonprio=10tid=0x00007f6da40cd000nid=
0x7a42waitingoncondition[0x0000000000000000]
SignalDispatcher"
daemonprio=10tid=0x00007f6da40cb00