Java中常见死锁与活锁的实例详解
本文介绍了Java中常见死锁与活锁的实例详解,分享给大家,具体如下:
- 顺序死锁:过度加锁,导致由于执行顺序的原因,互相持有对方正在等待的锁
- 资源死锁:多个线程在相同的资源上发生等待
由于调用顺序而产生的死锁
publicclassTest{ ObjectleftLock=newObject(); ObjectrightLock=newObject(); publicstaticvoidmain(String[]args){ finalTesttest=newTest(); Threada=newThread(newRunnable(){ @Overridepublicvoidrun(){ inti=0; while(i<10) { test.leftRight(); i++; } } },"aThread"); Threadb=newThread(newRunnable(){ @Overridepublicvoidrun(){ inti=0; while(i<10) { test.rightleft(); i++; } } },"bThread"); a.start(); b.start(); } publicvoidleftRight(){ synchronized(leftLock){ System.out.println(Thread.currentThread().getName()+":leftRight:getleft"); synchronized(rightLock){ System.out.println(Thread.currentThread().getName()+":leftRight:getright"); } } } publicvoidrightleft(){ synchronized(rightLock){ System.out.println(Thread.currentThread().getName()+":rightleft:getright"); synchronized(leftLock){ System.out.println(Thread.currentThread().getName()+":rightleft:getleft"); } } } }
运行后输出如下
aThread:leftRight:getleft
bThread:rightleft:getright
可以通过jstack发现死锁的痕迹
"bThread"prio=5tid=0x00007fabb2001000nid=0x5503waitingformonitorentry[0x000000011d54b000] java.lang.Thread.State:BLOCKED(onobjectmonitor) atmain.lockTest.Test.rightleft(Test.java:52) -waitingtolock<0x00000007aaee5748>(ajava.lang.Object) -locked<0x00000007aaee5758>(ajava.lang.Object) atmain.lockTest.Test$2.run(Test.java:30) atjava.lang.Thread.run(Thread.java:745) Lockedownablesynchronizers: -None "aThread"prio=5tid=0x00007fabb2801000nid=0x5303waitingformonitorentry[0x000000011d448000] java.lang.Thread.State:BLOCKED(onobjectmonitor) atmain.lockTest.Test.leftRight(Test.java:43) -waitingtolock<0x00000007aaee5758>(ajava.lang.Object) -locked<0x00000007aaee5748>(ajava.lang.Object) atmain.lockTest.Test$1.run(Test.java:19) atjava.lang.Thread.run(Thread.java:745) Lockedownablesynchronizers: -None
可以看到bThread持有锁0x00000007aaee5758,同时等待0x00000007aaee5748,然而恰好aThread持有锁0x00000007aaee5748并等待0x00000007aaee5758,从而形成了死锁
线程饥饿死锁
publicclassExecutorLock{ privatestaticExecutorServicesingle=Executors.newSingleThreadExecutor(); publicstaticclassAnotherCallableimplementsCallable{ @OverridepublicStringcall()throwsException{ System.out.println("inAnotherCallable"); return"annothersuccess"; } } publicstaticclassMyCallableimplementsCallable { @OverridepublicStringcall()throwsException{ System.out.println("inMyCallable"); Future submit=single.submit(newAnotherCallable()); return"success:"+submit.get(); } } publicstaticvoidmain(String[]args)throwsExecutionException,InterruptedException{ MyCallabletask=newMyCallable(); Future submit=single.submit(task); System.out.println(submit.get()); System.out.println("over"); single.shutdown(); } }
执行的输出只有一行
inMyCallable
通过jstack观察可以看到如下
"main"prio=5tid=0x00007fab3f000000nid=0x1303waitingoncondition[0x0000000107d63000] java.lang.Thread.State:WAITING(parking) atsun.misc.Unsafe.park(NativeMethod) -parkingtowaitfor<0x00000007aaeed1d8>(ajava.util.concurrent.FutureTask) atjava.util.concurrent.locks.LockSupport.park(LockSupport.java:186) atjava.util.concurrent.FutureTask.awaitDone(FutureTask.java:425) atjava.util.concurrent.FutureTask.get(FutureTask.java:187) atmain.lockTest.ExecutorLock.main(ExecutorLock.java:32) atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod) atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) atjava.lang.reflect.Method.invoke(Method.java:606) atcom.intellij.rt.execution.application.AppMain.main(AppMain.java:140) Lockedownablesynchronizers: -None .. "pool-1-thread-1"prio=5tid=0x00007fab3f835800nid=0x5303waitingoncondition[0x00000001199ee000] java.lang.Thread.State:WAITING(parking) atsun.misc.Unsafe.park(NativeMethod) -parkingtowaitfor<0x00000007ab0f8698>(ajava.util.concurrent.FutureTask) atjava.util.concurrent.locks.LockSupport.park(LockSupport.java:186) atjava.util.concurrent.FutureTask.awaitDone(FutureTask.java:425) atjava.util.concurrent.FutureTask.get(FutureTask.java:187) atmain.lockTest.ExecutorLock$MyCallable.call(ExecutorLock.java:26) atmain.lockTest.ExecutorLock$MyCallable.call(ExecutorLock.java:20) atjava.util.concurrent.FutureTask.run(FutureTask.java:262) atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) atjava.lang.Thread.run(Thread.java:745) Lockedownablesynchronizers: -<0x00000007aaeed258>(ajava.util.concurrent.ThreadPoolExecutor$Worker)
主线程在等待一个FutureTask完成,而线程池中一个线程也在等待一个FutureTask完成。
从代码实现可以看到,主线程往线程池中扔了一个任务A,任务A又往同一个线程池中扔了一个任务B,并等待B的完成,由于线程池中只有一个线程,这将导致B会被停留在阻塞队列中,而A还得等待B的完成,这也就是互相等待导致了死锁的反生
这种由于正在执行的任务线程都在等待其它工作队列中的任务而阻塞的现象称为线程饥饿死锁
活锁
并未产生线程阻塞,但是由于某种问题的存在,导致无法继续执行的情况。
1、消息重试。当某个消息处理失败的时候,一直重试,但重试由于某种原因,比如消息格式不对,导致解析失败,而它又被重试
这种时候一般是将不可修复的错误不要重试,或者是重试次数限定
2、相互协作的线程彼此响应从而修改自己状态,导致无法执行下去。比如两个很有礼貌的人在同一条路上相遇,彼此给对方让路,但是又在同一条路上遇到了。互相之间反复的避让下去
这种时候可以选择一个随机退让,使得具备一定的随机性
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。