一、死锁
概念:
是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁
死锁的发生必须具备以下四个必要条件。
1)互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
2)请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
3)不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
4)环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。
理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。
只要打破四个必要条件之一就能有效预防死锁的发生。
打破互斥条件:改造独占性资源为虚拟资源,大部分资源已无法改造。
打破不可抢占条件:当一进程占有一独占性资源后又申请一独占性资源而无法满足,则退出原占有的资源。
打破占有且申请条件:采用资源预先分配策略,即进程运行前申请全部资源,满足则运行,不然就等待,这样就不会占有且申请。
打破循环等待条件:实现资源有序分配策略,对所有设备实现分类编号,所有进程只能采用按序号递增的形式申请资源。
避免死锁常见的算法有有序资源分配法、银行家算法。
ReentrantLock
可以通过其他方法去拿锁
tryLock():尝试拿锁,拿到就往下运行,没拿到就释放锁。
二、活锁
概念
两个线程在尝试拿锁的机制中,发生多个线程之间互相谦让,不断发生同一个线程总是拿到同一把锁,在尝试拿另一把锁时因为拿不到,而将本来已经持有的锁释放的过程。
解决办法
每个线程休眠随机数,错开拿锁的时间。
三、线程饥饿
概念
低优先级的线程,总是拿不到执行时间(时间片)
解决办法
提高线程优先级。
四、CAS(Compare And Swap)
实现流程
1.先获取变量的值(旧值)
2.执行计算得到新的结果。
3.比较内存中的值和旧值是否相等。
4.相等则和内存数据进行交换。
5.不相等,重新操作,直到成功为止。
其中比较和交换操作是原子操作:要么都执行,要么都不执行。
由此原理可以去区分一下悲观锁和乐观锁
- 悲观锁:Synchroized,获得锁才能进行后续操作。
- 乐观锁:我先进行操作,再去判断可不可以写入内存。
问题
- ABA问题:中间已经发生了操作,只不过又变回之前的值。 版本戳
- 开销问题:线程一直自旋,循环。
- 只能对一个共享变量进行原子操作。(一个地址)