volatile、synchronized、lock有什么区别,以及在哪些场景下使用哪种方式?

来源:互联网 发布:苏联加入轴心国 知乎 编辑:程序博客网 时间:2024/04/28 11:08

[转]JVM锁机制volatile/synchronized/lock

2014-9-9阅读213 评论0

1.volatile实现原理

(1)聊聊并发(一)——深入分析Volatile的实现原理
--硬件级别锁实现,Lock前缀指令会引起处理器缓存(CPU高级缓存L1/L2/L3)回写到内存。一个处理器的缓存回写到内存会导致其他处理器的缓存无效。

2.JVM锁机制--synchronized

(1)深入JVM锁机制1-synchronized

--自旋锁、偏向锁

--synchronized的底层实现主要依靠Lock-Free的队列,基本思路是自旋后阻塞,竞争切换后继续竞争锁,稍微牺牲了公平性,但获得了高吞吐量。


(2)聊聊并发(二)——Java SE1.6中的Synchronized
--偏向锁—>轻量锁—>重量锁 比较


偏向锁

Hotspot的作者经过以往的研究发现大多数情况下锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出同步块时不需要花费CAS操作来加锁和解锁,而只需简单的测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁,如果测试成功,表示线程已经获得了锁,如果测试失败,则需要再测试下Mark Word中偏向锁的标识是否设置成1(表示当前是偏向锁),如果没有设置,则使用CAS竞争锁,如果设置了,则尝试使用CAS将对象头的偏向锁指向当前线程。

偏向锁的撤销:偏向锁使用了一种等到竞争出现才释放锁的机制,所以当其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁。偏向锁的撤销,需要等待全局安全点(在这个时间点上没有字节码正在执行),它会首先暂停拥有偏向锁的线程,然后检查持有偏向锁的线程是否活着,如果线程不处于活动状态,则将对象头设置成无锁状态,如果线程仍然活着,拥有偏向锁的栈会被执行,遍历偏向对象的锁记录,栈中的锁记录和对象头的Mark Word要么重新偏向于其他线程,要么恢复到无锁或者标记对象不适合作为偏向锁,最后唤醒暂停的线程。下图中的线程1演示了偏向锁初始化的流程,线程2演示了偏向锁撤销的流程。


轻量锁

即自旋锁


重量锁

即阻塞锁


锁的优缺点对比

偏向锁

加锁和解锁不需要额外的消耗,和执行非同步方法比仅存在纳秒级的差距。

如果线程间存在锁竞争,会带来额外的锁撤销的消耗。

适用于只有一个线程访问同步块场景。

轻量级锁

竞争的线程不会阻塞,提高了程序的响应速度。

如果始终得不到锁竞争的线程使用自旋会消耗CPU。

追求响应时间。

同步块执行速度非常快。

重量级锁

线程竞争不使用自旋,不会消耗CPU。

线程阻塞,响应时间缓慢。

追求吞吐量。

同步块执行速度较长。



(3)JVM锁实现探究1:synchronized初探


(4)JVM锁实现探究2:synchronized深探

锁升级机制:无锁—>偏向锁—>轻量锁—>重量锁

3.JVM锁机制AQS(AbstractQueuedSynchronizer)

(1)深入JVM锁机制2-Lock

--源码分析java.util.concurrent.AbstractQueuedSynchronizer类

Lock VS Synchronized

AbstractQueuedSynchronizer通过构造一个基于阻塞的CLH队列容纳所有的阻塞线程,而对该队列的操作均通过Lock-Free(CAS)操作,但对已经获得锁的线程而言,ReentrantLock实现了偏向锁的功能。

synchronized的底层也是一个基于CAS操作的等待队列,但JVM实现的更精细,把等待队列分为ContentionList和EntryList,目的是为了降低线程的出列速度;当然也实现了偏向锁,从数据结构来说二者设计没有本质区别。但synchronized还实现了自旋锁,并针对不同的系统和硬件体系进行了优化,而Lock则完全依靠系统阻塞挂起等待线程。

当然Lock比synchronized更适合在应用层扩展,可以继承AbstractQueuedSynchronizer定义各种实现,比如实现读写锁(ReadWriteLock),公平或不公平锁;同时,Lock对应的Condition也比wait/notify要方便的多、灵活的多。


4.ReentrantLock

(1)JAVA并发编程学习笔记之ReentrantLock

--ReentrantLock是一个可重入的互斥锁,ReentrantLock由最近成功获取锁,还没有释放的线程所拥有

(2)ReentrantLock与synchronized的区别

--ReentrantLock的lock机制有2种,忽略中断锁和响应中断锁

--synchronized实现的锁机制是可重入的,主要区别是中断控制和竞争锁公平策略

0 0
原创粉丝点击