学习Java基础知识,打通面试关~十四锁机制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fengruiqi/article/details/80963571

在java中,我们进行多线程操作的时候,一般都会用到锁的机制。并且在锁中我们一般用到的是synchronized和ReentrantLock两种,当然还有更加细化的读写锁。我们这里api的使用不讲解。在学习锁机制之前,我们需要了解几个概念。
* 原子性:相关操作中,不会被其他线程干扰,安全的运行到结束。一般通过同步操作来实现。
* 可见性:当某个线程修改了共享变量。其状态可以立刻让其他线程了解到。通常解释为本地内存数据反映到主内存上。关键字volative字就是这么做的。
* 有序性: 保持线程内的串行语义,避免指令重排。
在了解上面几个意义之后,我们开始学习下java中的锁机制。

synchronized

该锁在使用方式可以参考我原先写的java多线程系列文章
我们知道synchronized的锁机制是建立在monitorenter/monitorexit指令上的。基本单元是Monitor。
在jdk1.6之前Monitor之前主要是依赖操作系统内部的机制来实现同步的。这样实现的锁机制在执行时会消耗很大的资源,导致锁机制同步的很慢。
在jdk1.6以后锁机制进行了修改,主要修改的方向是在jvm上的修改。改变了锁机制采用了锁的升降级操作。里面涉及到的偏向锁,轻量级锁,重量级锁。
* 偏向锁:利用的机制也是CAS操作(compare and swap)
1. 这是一种加锁操作的优化。核心是 一个线程获得锁 ,那么就先会进入偏向模式。此时在MarkWord的节后也会变成偏向锁的结构。
2. 当当前线程要再次获取锁时。无需做同步操作直接获得,省去了中间的锁申请的操作。
3. 如果锁竞争比较激烈,那么偏向锁就会失败,进而升级为轻量级锁。
* 轻量级锁:
1. 偏向锁进行失败的时候或者关闭偏向锁时,升级为轻量级锁。在MarkWord中的结构也变为轻量级锁的结构。
2. 依据:对于大部分的锁而言,在整个周期内不存在竞争的关系。如果竞争激烈的情况下轻量级锁要比重量级锁效率更低。
3. 在 轻量级锁操作时,如果MarkWord已经不是指向当前线程的栈帧,那么说明该锁对象已经被其他线程占领,轻量级锁会膨胀微重量级锁,后面的线程会进入阻塞状态。
* 重量级锁
重量级锁是通过我们所说的Monitor基本单元实现的。。这是对象的内部监视器。该主要依赖底层的操作系统Mutex Lock实现,操作系统实现线程间的切换需要利用到用户态和内核态的切换。成本较高。

ReentrantLock

ReentrantLock建立在AQS(AbstractQueuedSynchronizer)的操作上的。
1. 该锁机制更加灵活方便,可以设置锁的公平性,获取释放锁等。
2. AbstractQueuedSynchronizer是独占的同步器,内部使用 exclusiveOwnerThread表示独占的线程,并且使用CLH锁队列来将并发执行改成串行执行,整个队列是一个双向的链表,每个CLH锁队列的节点会保存前一个节点和后一个节点的引用,当前节点对应的线程,一集一个状态。这个状态表示线程是否阻塞block.
3. 锁获取主要分为两个部分,第一阶段是初次进行竞争主要来烤火节点是否分为公平锁还是不公平锁。 第二阶段是在CHL队列中的锁,依赖CAS操作保证原子操作。使队列并发操作改成了串行操作。消除并发带来的问题
4.ReentrantLock 是一个轻量级的锁。
公众号

猜你喜欢

转载自blog.csdn.net/fengruiqi/article/details/80963571