互斥同步之锁机制
互斥同步是保证线程安全的一种手段,在Java中提供了两种锁机制来实现
- 同步锁synchronized
- Reentrant锁
锁机制虽然能有效地保证线程安全,但是其也存在问题:当线程因为请求锁进入阻塞或者等待被唤醒时,会给降低系统的性能。这是由于Java的线程实现是跟操作系统的线程绑定的,如果需要阻塞或者唤醒一个线程时,就需要用户态和内核态之间来回切换,应用在操作系统上的这种状态切换是很耗费CPU时间的,所以有可能对于非常简单的同步代码块,系统用于状态切换的时间要比执行同步代码的时间要长。所以锁机制的优化的目标就是尽可能降低线程进入阻塞/等待唤醒的概率,相关的技术有:
- 偏向锁
- 轻量锁
- 传统锁
- 同步锁和Reentrant锁的比较
比较项 | 同步锁 | Reetrant锁 |
---|---|---|
是否可重入 | 是 | 是 |
是否等待可中断 | 否 | 是 |
是否公平锁 | 否 | 是 |
是否可锁定多个条件 | 锁定一个 | 锁定多个 |
- 锁的状态转换
锁的状态转化.jpg
偏向锁和轻量级锁带来的优化的前提是假设多线程在锁对象的同步周期内都不存在竞争;
在Java中锁的状态切换顺序为偏向锁-->轻量级锁-->重量级锁(传统锁)
当程序中虽然写了同步的代码,但是实际上每次只有一个线程在请求锁,锁对象处于偏向锁;
当出现另外一个线程再请求锁时,锁对象就由偏向锁转为轻量锁。
如果每次都是一个线程获取锁,执行完同步代码块,释放锁后才有另一个线程来请求锁,则锁对象会一直处于轻量锁;
如果在某一时刻出现至少两个线程同时请求一把锁时,锁对象就由轻量锁升级为重量级锁。
详细的实现机制请参考:
http://luojinping.com/2015/07/09/java%E9%94%81%E4%BC%98%E5%8C%96/