死锁:
两个或者多个进程竞争统一资源而形成的僵持的局面,若无外力作用,将无法推进。
本质原因:
1)系统资源有限
2)进程推进顺序不合理
死锁的条件:
(1)互斥。某个资源在一段时间只能有一个进程占有,只有当使用该资源的进程释放后,其他进程才能占有该资源。
(2)请求和保持。进程A已经拥有了一些资源,现在要访问其他资源,A进程阻塞,但是在A等待的过程中,不会释放已有的资源,
(3)不剥夺。不可抢占条件,进程在未使用完资源之前,不能被其他进程抢占,只能由该进程的占有者自行释放。
(4)环路等待。存在一个等待序列{P1,P2,P3...Pn},其中,P1等待P2所占有的资源,P2等待P3所占有的某种资源,Pn等待P1占有的某种资源。
上述4个条件只要有1个不满足,死锁就会排除。
解决死锁的方法:
死锁的预防,避免,检测与恢复
预防:确保系统永远不会进入死锁状态。打破4个条件中的一个或者几个
避免:在使用前进行判断,只允许不会产生死锁的进程申请资源。安全序列,银行家算法,加锁顺序
检测与解除:检测到运行系统进入死锁,进行恢复。允许系统进入死锁状态。
乐观锁:
假设不会发生并发冲突。只在提交时是否违反数据完整性。不能解决脏读的问题。适用于并发量非常大的情况。
每次拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断在此期间别人有没有更新这个数据,可以使用版本号等机制。适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制。java.util.concurrent.atomic包下的原子变量类就是使用乐观锁的一种实现CAS实现的。
hibernate乐观锁的实现:
基于version,版本号
基于timestamp,时间戳
悲观锁:
假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。
每次去拿数据的时候都认为别人会修改,所以每次拿数据的时候都会上锁,这样别人想拿这个数据时就会阻塞直到它拿到锁。传统的关系型数据库就用到了很多这种锁机制,比如行锁,表锁,读锁,写锁等,都是在操作之前先上锁。java里面的synchronized关键字就是悲观锁。并发访问性不好。
并发量不大,不允许脏读的情况下使用悲观锁