多线程与锁(4)
-
死锁的原因
- 当前线程拥有其他线程需要的资源
- 当前线程等待其他线程已拥有的资源
- 都不放弃⾃⼰拥有的资源
-
死锁的条件
- 互斥条件:该资源任意一个时刻只由一个线程占用。
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:线程已获得的资源在末使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
-
破坏死锁
-
破坏互斥条件
这个条件我们没有办法破坏,因为我们用锁本来就是想让他们互斥的(临界资源需要互斥访问)。
-
破坏请求与保持条件
一次性申请所有的资源。
-
破坏不剥夺条件
占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
-
破坏循环等待条件
靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。
-
-
死锁检测工具
- JConsole
- Jstack
-
总结
-
线程之间交错执⾏
- 解决:以固定的顺序加锁
-
执⾏某⽅法时就需要持有锁,且不释放
- 解决:缩减同步代码块范围,最好仅操作共享变量时才加锁
-
永久等待
- 解决:使⽤ tryLock() 定时锁,超过时限则返回错误信息
-
-
常用线程工具类
-
CountDownLatch(闭锁)
- await()
- 等待其他线程countDown至0才进入await后的代码
- countDown()
- await()
-
CyclicBarrier(栅栏)
- await()
- 等待同一个CyclicBarrier对象的线程组到await方法再一起向下执行
- await()
-
Semaphore(信号量)
-
acquire()
-
release()
- 控制同时访问的线程个数,acquire current信号量+1 release current信号量-1 不得超过Semaphore对象的数
-
-
-
ThreadLocal
- 线程隔离的线程独有变量
- 原理
- 每个Thread维护着⼀个ThreadLocalMap的引⽤
- ThreadLocalMap是ThreadLocal的内部类,⽤Entry来进⾏存储
- 调⽤ThreadLocal的set()⽅法时,实际上就是往ThreadLocalMap设置值,key是ThreadLocal对象,值是传递进来的对象
- ThreadLocal本身并不存储值,它只是作为⼀个key来让线程从ThreadLocalMap获取value。