ReentrantLock简单使用demo以下:java
Lock lock = new ReentrantLock(); lock.lock(); try { //业务逻辑 } finally { lock.unlock(); }
注:获取的锁代码要放到try块以外,防止得到锁代码异常,抛出异常的同时,也会致使一次锁的释放。释放代码必定要放到finally块中。node
** AQS **
了解java中的锁,首先的了解AQS。
AQS(AbstractQueuedSynchronizer)队列同步器。是用来构建锁或者其它同步组件的基础框架,他实现了一个int成员变量标识同步状态(更改这个变量值来获取和释放锁),经过内置的FIFO双向队列来完成资源获取线程排队的工做。
AQS能够实现独占锁和共享锁,RenntrantLock实现的是独占锁,ReentrantReadWriteLock实现的是独占锁和共享锁,CountDownLatch实现的是共享锁。安全
ReentrantLock 类结构信息以下图:并发
** 公平锁和非公平锁 **框架
ReentrantLock 有两种实现方式,公平锁和非公平锁。ui
公平锁:当前线程不马上得到锁,而是先直进入等待队列中队尾进行排队获取锁。this
非公平锁:当前线程首先尝试获取一下锁(仅仅尝试一下),若是获取不到,则乖乖的进入到等待队列中去排队。线程
ReentrantLock实现公平锁和非公平锁代码以下:code
/** * Creates an instance of {@code ReentrantLock}. * This is equivalent to using {@code ReentrantLock(false)}. */ public ReentrantLock() { sync = new NonfairSync(); } /** * Creates an instance of {@code ReentrantLock} with the * given fairness policy. * * @param fair {@code true} if this lock should use a fair ordering policy */ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
** 获取非公平锁 **orm
/** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
/** * Performs non-fair tryLock. tryAcquire is implemented in * subclasses, but both need nonfair try for trylock method. */ final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
tryAcquire调用nonfairTryAcquire方法来第二次尝试得到锁
private Node addWaiter(Node mode) { Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure Node pred = tail; if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } enq(node); return node; }
将构造的同步节点加入到同步队列中
private Node enq(final Node node) { for (;;) { Node t = tail; if (t == null) { // Must initialize if (compareAndSetHead(new Node())) tail = head; } else { node.prev = t; if (compareAndSetTail(t, node)) { t.next = node; return t; } } } }
该方法使用CAS自旋的方式来保证向队列中添加Node(同步节点简写Node)
final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
在acquireQueued方法中,当前线程在死循环中尝试获取同步状态,
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { int ws = pred.waitStatus; if (ws == Node.SIGNAL) /* * This node has already set status asking a release * to signal it, so it can safely park. */ return true; if (ws > 0) { /* * Predecessor was cancelled. Skip over predecessors and * indicate retry. */ do { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); pred.next = node; } else { /* * 尝试将当前节点的前驱节点的等待状态设为SIGNAL * 1/这为何用CAS,如今已经入队成功了,前驱节点就是pred,除了node外应该没有别的线程在操做这个节点了,那为何还要用CAS?而不直接赋值呢? * (解释:由于pred能够本身将本身的状态改成cancel,也就是pred的状态可能同时会有两条线程(pred和node)去操做) * 2/既然前驱节点已经设为SIGNAL了,为何最后还要返回false * (由于CAS可能会失败,这里无论失败与否,都返回false,下一次执行该方法的以后,pred的等待状态就是SIGNAL了) */ compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } return false; }
waitStatus状态值
状态 | 值 | 说明 |
---|---|---|
CANCELLED | 1 | 等待超时或者中断,须要从同步队列中取消 |
SIGNAL | -1 | 后继节点出于等待状态,当前节点释放锁后将会唤醒后继节点 |
CONDITION | -2 | 节点在等待队列中,节点线程等待在Condition上,其它线程对Condition调用signal()方法后,该节点将会从等待同步队列中移到同步队列中,而后等待获取锁。 |
PROPAGATE | -3 | 表示下一次共享式同步状态获取将会无条件地传播下去 |
INITIAL | 0 | 初始状态 |
private final boolean parkAndCheckInterrupt() { LockSupport.park(this); return Thread.interrupted(); }
把当前线程挂起,并检查刚线程是否执行了interrupted方法,并返回true、false。
** 公平锁 **
公平锁和非公平锁实现方式是同样的,惟一不一样的是tryAcquire方法的实现,下面是公平锁tryAcquire方法实现:
protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }