本文共 2357 字,大约阅读时间需要 7 分钟。
认为数据在一般情况下不会造成冲突,所以在访问记录前不会加排它锁;
在进行数据提交更新时,才会正式对数据冲突与否进行检测;
乐观锁并不会使用数据库提供的锁机制,一般在表中添加version字段或者使用业务状态来实现;
乐观锁直到提交时才锁定,所以不会产生任何死锁。
指对数据被外界修改保持保守态度,认为数据很容易就被其他线程修改;
在数据被处理前先对数据进行加锁,并在整个数据处理过程中,使数据处于锁定状态;
悲观锁的实现往往依靠数据库提供的锁机制。
在运行时闯入,根据具体调度方法确定顺序
使用ReentrantLock方法来实现
当一个线程再次获取它自己已经获取的锁时不被阻塞,就说该锁时可重入的。
原理:在锁内部维护一个线程标识,用来标识该锁目前被那个线程占用,然后关联一个计数器。
计数器初始值为0,说明该锁没有被任何线程占用。当一个线程获取了该锁时,计数器的值为1,这时其他线程再来获取该锁时会发现所有者不是自己而被挂起。当获取了该锁的线程再次获取锁时发现锁拥有者是自己,则计数器值+1,释放锁后计数器值-1.当锁里面的表示被重置为null时,被阻塞的线程会被唤醒来竞争获取该锁。
定义
当前线程在获取锁时,如果发现锁已经被其他线程占有,它不马上阻塞自己,在不放弃CPU使用权的情况下,多次尝试获取,很有可能在后面几次尝试中其他线程已经释放了锁。缺点
单核处理器上,不存在实际的并行,当前线程不阻塞自己的话,旧owner就不能执行,锁永远不会释放,此时不管自旋多久都是浪费;进而,如果线程多而处理器少,自旋也会造成不少无谓的浪费。
自旋锁要占用CPU,如果是计算密集型任务,这一优化通常得不偿失,减少锁的使用是更好的选择。
如果锁竞争的时间比较长,那么自旋通常不能获得锁,白白浪费了自旋占用的CPU时间。这通常发生在锁持有时间长,且竞争激烈的场景中,此时应主动禁用自旋锁。
自适应意味着自旋的时间不再固定了,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定:
如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也很有可能再次成功,进而它将允许自旋等待持续相对更长的时间,比如100个循环。
相反的,如果对于某个锁,自旋很少成功获得过,那在以后要获取这个锁时将可能减少自旋时间甚至省略自旋过程,以避免浪费处理器资源。
自适应自旋解决的是“锁竞争时间不确定”的问题。自适应自旋假定不同线程持有同一个锁对象的时间基本相当,竞争程度趋于稳定,因此,可以根据上一次自旋的时间与结果调整下一次自旋的时间。然而,自适应自旋也没能彻底解决该问题,如果默认的自旋次数设置不合理(过高或过低),那么自适应的过程将很难收敛到合适的值。
定义
偏向锁的目标是,减少无竞争且只有一个线程使用锁的情况下,使用轻量级锁产生的性能消耗。轻量级锁每次申请、释放锁都至少需要一次CAS,但偏向锁只有初始化时需要一次CAS。
偏向锁假定将来只有第一个申请锁的线程会使用锁(不会有任何线程再来申请锁),因此,只需要在Mark Word中CAS记录owner(本质上也是更新,但初始值为空),如果记录成功,则偏向锁获取成功,记录锁状态为偏向锁,以后当前线程等于owner就可以零成本的直接获得锁;否则,说明有其他线程竞争,膨胀为轻量级锁。
缺点
如果明显存在其他线程申请锁,那么偏向锁将很快膨胀为轻量级锁。
根据锁只能被单线程持有还是能被多个线程共同持有,可以分为独占锁和共享锁。
偏向锁、轻量级锁、重量级锁适用于不同的并发场景:
偏向锁:无实际竞争,且将来只有第一个申请锁的线程会使用锁。
轻量级锁:无实际竞争,多个线程交替使用锁;允许短时间的锁竞争。
重量级锁:有实际竞争,且锁竞争时间长。
另外,如果锁竞争时间短,可以使用自旋锁进一步优化轻量级锁、重量级锁的性能,减少线程切换。如果锁竞争程度逐渐提高(缓慢),那么从偏向锁逐步膨胀到重量锁,能够提高系统的整体性能。
锁的升级和降级
所得升级、降级,就是JVM优化synchronized运行的机制,当JVM检测到不同的竞争状况时,会自动切换到适合的锁实现,这种切换就是锁的升级、降级。(如从偏向锁到轻量级锁再到重量级锁)转载地址:http://uyzci.baihongyu.com/