- 开始是乐观锁,如果冲突频繁,就转换为悲观锁
- 开始时轻量级锁实现,如果锁被持有的时间较长,则转换为重量级锁
- 实现轻量级锁的时候大概要用到自旋锁
- 是一种不公平锁
- 不是读写锁
JVM将synchronized锁分为无锁,偏向锁,轻量级锁,重量级锁状态。会根据竞争的激烈程度,动态选择锁的实现
没有任何线程尝试获取锁
偏向锁当有第一个线程(t1)尝试获取锁,JVM分配偏向锁给t1线程。当这个t1线程再次获取锁时(重入或是再次执行),没有加锁和解锁的过程,从而降低程序的开销,就验证一下锁的持有线程是否是t1,若是直接放行。
轻量级锁当有第二个线程(t2)在t1执行完后尝试获取锁,JVM就会取消偏向锁状态,将锁升级为轻量级锁。
使用CAS(自旋锁来实现)来进行轻量级锁的获取,有加锁和解锁的过程,就是通过自旋来进行的
t2线程尝试通过自旋的方式来获取轻量级锁,还有其他线程t3…t4在t2还没结束的时候尝试获取锁,都在自旋等待t2执行结束
重量级锁当竞争非常激烈的时候,多个线程同时在竞争轻量级锁(一般来说就是当前线程数等于CPU核数的一半),或者自旋次数超过10次(默认值),也会将轻量级锁碰撞为重量级锁(竞争比较激烈,为了避免CPU空泡,就将线程阻塞)。
重量级锁是悲观锁的一种实现,依赖操作系统提供的mutex来实现,会从用户态切换到内核态,获取重量级锁失败的线程会进入阻塞状态。
ReentrantLock(可重入锁)在java中除了synchronized关键字可以实现对象锁之外,java中的Lock接口的子类ReentrantLock也可以实现对象锁
ReentrantLock 的用法:- lock(): 加锁, 如果获取不到锁就死等.
- trylock(超时时间):加锁,如果获取不到锁,等待一段时间后就放弃加锁
- unlock():解锁
- synchronized是Java的关键字,由JVM实现,需要依赖操作系统提供的线程互斥原语(mutex)实现;ReentrantLock是Java标准库的一个类,基于Java实现,不依赖操作系统
- synchronized由JVM自动加锁和解锁,不需要手动加锁和解锁。ReentrantLock需要手动加锁和解锁,使用起来更灵活,但也容易遗漏unlock
- synchronized加锁失败会死等;ReentrantLock通过trylock方法等待一段时间就可以放弃等待
- synchronized是非公平锁;ReentrantLock默认是非公平锁,可以通过可以通过构造方法传入一个 true 开启 公平锁模式
- 更强大的唤醒机制. synchronized 是通过 Object 的 wait / notify 实现等待-唤醒. 每次唤醒的是一 个随机等待的线程. ReentrantLock 搭配 Condition 类实现等待-唤醒, 可以更精确控制唤醒某个指 定的线程.
- ReentrantLock 和 synchronized都不支持读写锁,要想实现读写锁可以使用Lock子类ReentrantReadWriteLock
- 当竞争不激烈时,使用synchronized效率更高,自动释放锁
- 当锁竞争激烈时,使用ReentrantLock搭配try lock更灵活控制加锁行为,而不是死等
- 如果需要使用公平锁, 使用 ReentrantLock.



