浅析 ReentrantLock对象和synchronized关键字
浅析 ReentrantLock对象和synchronized关键字
看过suhuanzheng7784877同学的并发加锁机制后,然后结合自己的一些理解也来讲讲锁,以便日后回顾和复习。
在我接触的锁机制的有两种锁,一种就是单原子加锁, 一种就是synchronized加锁,而前者是通过程序控制单原子变量实现,而后者是有jvm控制。
先不说执行的效率,竟然程序也能实现锁,让我们看看锁到底怎么实现的,ReentrantLock就是实现了单原子加锁。
先想想什么是单原子加锁? 在我所接触当中,我的理解是通过程序控制基本类型数据。一般是通过 int 数据,及申明一个int变量,我们通过程序维护它的并发。
所以,说一种最简单的最通俗的 就是:当一个线程使用某个对象的时候,先判断该对象里面的int变量, 如果是0说明还没有线程使用它, 如果是1,说明有线程使用它,所以就进入等待(这里是需要靠程序实现的)。
那么我们就来看看ConcurrentHashMap类吧,先简单的介绍下它,它和hashTable的功能差不多都是实现了同步功能。
那么在ConcurrentHashMap里面就有一个Segment对象(差不多ConcurrentHashMap的方法都是调用Segment方法,所以我们先不去想ConcurrentHashMap也不谈它的特性,就直接看Segment的put方法):
V put(K key, int hash, V value, boolean onlyIfAbsent) { lock(); try { 。。。。。。省略了 } finally { unlock(); } }接着看lock()方法(这里的lock方法就是ReentrantLock里面的,Segment是继承于ReentrantLock,而Segment是ConcurrentHashMap的对象数组)
final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }中间省略了一些步骤,这个lock方法是NonfairSync里面的实现,ReentrantLock默认都是使用的这个方法。compareAndSetState这个方法主要的作用是判断,如果第一个参数等于 锁对象里面的state(单原子锁变量)变量的值(及没有线程占用),及获得这把锁同时把值改为1。如果返回true就把当前线程设置为独占线程,否则尝试第二种解锁。
在解释第二种锁之前先了解下NonfairSync的超父类AbstractQueuedSynchronizer,简单的说明下,里面含有 state变量和Node节点(链表结构(数据储存的是线程))对象,
不多说贴出 acquire(1)实现的代码:
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }final boolean acquireQueued(final Node node, int arg) { try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } catch (RuntimeException ex) { cancelAcquire(node); throw ex; } }不多说代码贴出来,shouldParkAfterFailedAcquire() 如果没有成功把当前线程加入到队列中等待, 这就是实现了锁的过程,当然很多方法都是本地代码实现的。
解锁就不说了,
那么现在谈谈 synchronized ,它是依靠jvm实现的,
我猜想的是有jvm内部监听器实现,如下图:

这个也不好多说,就写到这里吧!