目录
悲观锁 通常用在多写场景
悲观锁假设总是最坏的情况,每次去访问公共资源时,都认为可能会出现问题,共享资源可能会被其他线程修改,所以每次访问公共资源的时候,对其进行加锁。其他线程想要访问该资源,就要被阻塞,一直到上一条线程执行完毕释放锁。
Synchronnized和ReentrantLock都是悲观锁的实现。
问题:高并发场景下,可能会造成大量的锁阻塞,并且还有死锁问题。
Synchronized
底层原理
本质都是获取锁监视器monitor的过程,默认是非公平锁。
修饰代码块,锁的是给定对象
monitorenter指令是获取锁,如果锁计数器是0,则表示可以获取锁,获取锁之后,锁计数器+1。获取锁失败就进入阻塞队列,等待下一次时间片的抢夺。
monitorexit指令是持有锁的线程释放锁的指令,释放锁之后,锁计数器-1,其他线程就可以获取锁了。
修饰方法
修饰实例方法,锁的是当前对象
修饰静态方法,锁的是当前类
使用ACC_SYNCHRONNIZED来标识一个是一个同步方法,
ReentrantLock
原理:基于AQS,是一个可重入且独占锁,默认是非公平锁,可以通过构造器显式指定公平锁。
相比Synchronized,ReentrantLock
更灵活、更强大,增加了轮询、超时、中断、公平锁和非公平锁等高级功能。
Synchronized和ReentrantLock比较
1、都是可重入锁(递归锁),否则会造成死锁问题。
2、synchronized是基于JVM,而ReentrantLock是基于Jdk的API。
3、ReentrantLock比Synchronized增加了很多高级功能
等待可中断、可实现公平锁、可选择性通知
乐观锁 通常用在多读场景
乐观锁假设总是最好的情况,每次访问资源都不会认为会出现问题,不会加锁也不会阻塞,可以一直运行。每次去修改时,需要校验对应资源有没有被修改过,如果有,则重新执行修改逻辑,如果没有,就提交修改。
CAS就是典型的乐观锁。
CAS的问题
问题:高并发场景下,如果写操作比较多的话,可能会造成频繁失败和重试,CPU压力过大。
CAS问题:ABA问题——CAS每次去修改值的之后,如果预期值A被其他线程修改为B,再修改为A,这个过程当前线程是不知道的。
解决方案:使用版本号机制或时间戳或标记字段都可以。
CAS问题:循环消耗大,失败重试直到成功。
解决方案:限制重试次数,一般限制为3次
标签:Synchronized,CAS,ReentrantLock,乐观,修改,线程,悲观,修饰 From: https://blog.csdn.net/weixin_45967584/article/details/137014353