- 浏览: 984398 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
AtomicInteger解析:http://donald-draper.iteye.com/blog/2359555
锁持有者管理器AbstractOwnableSynchronizer:http://donald-draper.iteye.com/blog/2360109
AQS线程挂起辅助类LockSupport:http://donald-draper.iteye.com/blog/2360206
AQS详解-CLH队列,线程等待状态:http://donald-draper.iteye.com/blog/2360256
AQS-Condition详解:http://donald-draper.iteye.com/blog/2360381
从上面可以看出ReentrantLock关联一个同步锁SYNC,内部的SYNC是基于AQS实现的。
同步锁SYNC有两种实现,公平锁与非公平锁;ReentrantLock默认创建的是非公平锁。
下面再来看一下公平锁与非公平锁,先看非公平锁
//AQS
先看
再看
最后再看
//添加独占模式等待节点
再看
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
这个方法我们在Condition那篇文章中说过,
首次查看节点的前驱节点线程,是否是头节点,如果时,则尝试获取
锁,如果成功,则设置节点为头节点;否则检查当是否应该再获取锁的时候
,唤醒后继节点;如果尝试获取锁失败,则park当前线程,如果失败,则整个
过程失败,从队列中移除当前线程节点。
自旋请求锁,如果可能的话挂起线程,直到得到锁,返回当前线程是否中断过
(如果park()过并且中断过的话有一个interrupted中断位)。
。acquireQueued过程是这样的:
1. 如果当前节点是AQS队列的头结点(如果第一个节点是DUMP节点也就是傀儡节点,
那么第二个节点实际上就是头结点了),就尝试在此获取锁tryAcquire(arg)。
如果成功就将头结点设置为当前节点(不管第一个结点是否是DUMP节点),返回中断位。否则进行2。
2. 检测当前节点是否应该park(),如果应该park()就挂起当前线程并且返回当前线程中断位。进行操作1。
最后再看
再看公平锁
我们再回到SYNC的nonfairTryAcquire方法,非公平尝试获取锁;
//SYNC
比较非公平锁的尝试获取锁nonfairTryAcquire与公平锁TryAcquire的区别在与
非公平尝试获取锁时,如果锁为打开状态,则锁住锁;而公平锁,则先看有没有前驱节点
,有前驱,则不能锁住锁,没有则可锁住。
我们再对比一下公平锁和非公平锁的lock方法
从上面可以看出,非公平锁与公平锁lock的时候,最大的不同是非公平锁,
先以CAS的方式锁住锁,在进行acquire操作,而公平锁,直接acquire操作。
再来看可重入锁的其他方法
//ReentrantLock
//AQS
自旋请求锁,如果可能的话挂起线程,直到得到锁;在这一过程中,如果获取失败,且可park当前线程,则park当前线程,再判断是否可以中断,可以则抛出中断异常。
总结:
可重入自旋锁,当线程持有锁,可以多次获取锁,但最多只有2^31-1次;获取失败时,添加到同步等待队列自旋,直到获取锁成功;ReentrantLock关联一个同步锁SYNC,内部的SYNC是基于AQS实现的。同步锁SYNC有两种实现,公平锁与非公平锁;ReentrantLock默认创建的是非公平锁。比较非公平锁的尝试获取锁nonfairTryAcquire与公平锁TryAcquire的区别在于,非公平尝试获取锁时,如果锁为打开状态,则锁住锁;而公平锁,则先看有没有前驱节点,有前驱,则不能锁住锁,没有则可锁住。公平锁与公平锁lock,最大的不同是非公平锁,先以CAS的方式锁住锁,在进行acquire操作,而公平锁,直接acquire操作。
acquire操作主要过程为,自旋,检查节点的前驱节点是否为头节点,如果是,当前节点为同步队列的第一个节点,则尝试获取锁,如果成功,设置头结点为当前节点,否则判断尝试获取锁失败,是否应该park,如果需要park,则park当前线程,park后,检查是否可中断当前线程,如果可,则中断当前线程。
附:
锁持有者管理器AbstractOwnableSynchronizer:http://donald-draper.iteye.com/blog/2360109
AQS线程挂起辅助类LockSupport:http://donald-draper.iteye.com/blog/2360206
AQS详解-CLH队列,线程等待状态:http://donald-draper.iteye.com/blog/2360256
AQS-Condition详解:http://donald-draper.iteye.com/blog/2360381
/* * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/publicdomain/zero/1.0/ */ 前面的文章中,我们看了CAS原理和AQS机制,今天我们来看已下可重入锁ReentrantLock。 ReentrantLock本质上一种独占锁,获取锁方式有公平与非公平获取锁方式。 import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; /** * A reentrant mutual exclusion {@link Lock} with the same basic * behavior and semantics as the implicit monitor lock accessed using * {@code synchronized} methods and statements, but with extended * capabilities. * 一个与implicit monitor lock具有相同功能的可扩展的可重入互质锁。 * <p>A {@code ReentrantLock} is [i]owned[/i] by the thread last * successfully locking, but not yet unlocking it. A thread invoking * {@code lock} will return, successfully acquiring the lock, when * the lock is not owned by another thread. The method will return * immediately if the current thread already owns the lock. This can * be checked using methods {@link #isHeldByCurrentThread}, and {@link * #getHoldCount}. 可重入锁,被上次成功获取锁,还没释放的线程,所拥有的;当锁没有被其他线程所 持有,线程可以调用lock函数,获取锁;当锁的持有者为当前线程,当前线程调用lock函数, 立刻返回,并获取锁;可用isHeldByCurrentThread方法,判断锁是否被当前单线程所持有, 用getHoldCount获取当前线程,持有锁的次数(在线程持有锁,再次调用lock,成功获取锁的次数)。 * * <p>The constructor for this class accepts an optional * [i]fairness[/i] parameter. When set {@code true}, under * contention, locks favor granting access to the longest-waiting * thread. Otherwise this lock does not guarantee any particular * access order. Programs using fair locks accessed by many threads * may display lower overall throughput (i.e., are slower; often much * slower) than those using the default setting, but have smaller * variances in times to obtain locks and guarantee lack of * starvation. Note however, that fairness of locks does not guarantee * fairness of thread scheduling. Thus, one of many threads using a * fair lock may obtain it multiple times in succession while other * active threads are not progressing and not currently holding the * lock. * Also note that the untimed {@link #tryLock() tryLock} method does not * honor the fairness setting. It will succeed if the lock * is available even if other threads are waiting. * ReentrantLock的构造函数有一个公平性参数boolean,来确定,可重入锁是公平锁,还是非公平锁。 如果是公平锁,当锁没有持有者时,将锁授予,最早等待获取锁的线程;非公平锁,不能保证按照 获取锁的顺序,将锁的授予线程;非公平锁在性能上,更优一些,但在获取锁的尝试次数和保证 lack of starvation(锁的饥渴性,暂时这么翻译)上,两种锁没有太多的差别。公平锁,也不能 绝对的保证公平性,比如,当其他的线程等待锁的时候,一个线程持有锁,也许在持有锁的过程中, 多次获取锁。tryLock也不能保证公平性,即使其他的线程在等待锁,一个线程持有锁,调用tryLock 如果锁可利用,则线程获取锁成功。 为什么,非公平锁的性能比公平锁要高呢?假设现在有一些线程在等待锁,当锁被持有者释放时, 这时,正好有一个线程获取锁,非公平锁则获取成功,公平锁则要从锁等待队列线程中,唤醒一个线程 ,进入就绪运行状态,切换上下文,倒不如,让正在请求锁的线程,直接获取锁。 * <p>It is recommended practice to [i]always[/i] immediately * follow a call to {@code lock} with a {@code try} block, most * typically in a before/after construction such as: * 在使用ReentrantLock时候,强烈建议在获取锁后面使用try语句块,以便在 finally中释放锁,如下 * <pre> * class X { * private final ReentrantLock lock = new ReentrantLock(); * // ... * * public void m() { * lock.lock(); // block until condition holds * try { * // ... method body * } finally { * lock.unlock() * } * } * } * </pre> * * <p>In addition to implementing the {@link Lock} interface, this * class defines methods {@code isLocked} and * {@code getLockQueueLength}, as well as some associated * {@code protected} access methods that may be useful for * instrumentation and monitoring. 对于实现可重入锁ReentrantLock,除了Lock中的方法外,还可以调用 ReentrantLock锁的isLocked和getLockQueueLength方法,和一些protected的 方法,以便监视锁的状态 * * <p>Serialization of this class behaves in the same way as built-in * locks: a deserialized lock is in the unlocked state, regardless of * its state when serialized. * 序列化可重入锁ReentrantLock,则忽略锁状态,反序列化时,锁处于unlocked state; * <p>This lock supports a maximum of 2147483647 recursive locks by * the same thread. Attempts to exceed this limit result in * {@link Error} throws from locking methods. *一个线程可以持有锁的次数为2147483647(2^31-1),当尝试次数,超过最大限制时,则 抛出异常,如果线程在持有2147483647次的情况下,再TryAcquire,则锁的持有数为-1; 超过整数范围溢出; * @since 1.5 * @author Doug Lea */ public class ReentrantLock implements Lock, java.io.Serializable { private static final long serialVersionUID = 7373984872572414699L; //同步器,提供所有锁机制 /** Synchronizer providing all implementation mechanics */ private final Sync sync; /** * Base of synchronization control for this lock. Subclassed * into fair and nonfair versions below. Uses AQS state to * represent the number of holds on the lock. */ //可重入锁,依赖于同步Sync,同步是基于AQS的实现;同步Sync //有两种实现一种是公平锁,一种是非公平锁;用AQS state表示,锁的状态。 abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; /** * Performs {@link Lock#lock}. The main reason for subclassing * is to allow fast path for nonfair version. */ 在非公平锁实现中,允许快速获取锁 abstract void lock(); /** * Performs non-fair tryLock. tryAcquire is * implemented in subclasses, but both need nonfair * try for trylock method. */ //在非公平锁的尝试获取锁方法中,会调用nonfairTryAcquire //acquires为尝试获取次数,一般为1 final boolean nonfairTryAcquire(int acquires) { //获取当前线程 final Thread current = Thread.currentThread(); int c = getState();//获取锁状态 if (c == 0) {//如果没有线程持有锁 if (compareAndSetState(0, acquires)) { //尝试获取锁,如果获取成功,则设置锁的持有者,为当前线程,返回ture setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { //如果锁被线程持有,判断持有者是不是当前线程; //如果当前线程是锁的持有者,则锁被当前线程持有的次数+获取次数acquires int nextc = c + acquires; if (nextc < 0) // overflow //如果锁被线程连续持有次数,小于0,则超出,一个线程可以连续持有锁的最大次数 //抛出异常 throw new Error("Maximum lock count exceeded"); //否则,设置锁状态,返回true setState(nextc); return true; } //锁被持有,且持有者非当前线程,返回false,获取锁失败。 return false; } //尝试释放锁,releases释放次数 protected final boolean tryRelease(int releases) { //获取释放releases次锁后的锁状态。 int c = getState() - releases; //如果当前线程非锁持有者,抛出状态监控异常 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; //如果锁持有者线程释放,releases次后,锁状态为打开 if (c == 0) { //释放锁成功 free = true; //设置锁持有者为NULL setExclusiveOwnerThread(null); } //如果,释放releases次后,线程仍持有锁,设置锁状态,释放失败。 setState(c); return free; } //检查锁持有者是否为当前线程 protected final boolean isHeldExclusively() { // While we must in general read state before owner, // we don't need to do so to check if current thread is owner return getExclusiveOwnerThread() == Thread.currentThread(); } //创建条件,这个我们在前面讲过 final ConditionObject newCondition() { return new ConditionObject(); } // Methods relayed from outer class //获取锁持有者线程,无持有者,则为null final Thread getOwner() { return getState() == 0 ? null : getExclusiveOwnerThread(); } //获取线程连续持有锁的次数,如果是当前线程持有锁,则返回state,否则为0 final int getHoldCount() { return isHeldExclusively() ? getState() : 0; } //锁是否被持有 final boolean isLocked() { return getState() != 0; } /** * Reconstitutes this lock instance from a stream. * @param s the stream */ //反序列化锁,设置锁为打开状态 private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state } } /** * 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(); } static final class NonfairSync extends Sync {} static final class FairSync extends Sync {} }
从上面可以看出ReentrantLock关联一个同步锁SYNC,内部的SYNC是基于AQS实现的。
同步锁SYNC有两种实现,公平锁与非公平锁;ReentrantLock默认创建的是非公平锁。
下面再来看一下公平锁与非公平锁,先看非公平锁
/** * Sync object for non-fair locks */ static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { //先以CAS方式获取锁,如果获取成功,设置当前线程为锁,持有者 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else //否则,这一步我们单看 acquire(1); } //尝试获取锁,acquires次,一般为1 protected final boolean tryAcquire(int acquires) { //以非公平的方式获取锁 return nonfairTryAcquire(acquires); } }
//AQS
/** * Acquires in exclusive mode, ignoring interrupts. Implemented * by invoking at least once {@link #tryAcquire}, * returning on success. Otherwise the thread is queued, possibly * repeatedly blocking and unblocking, invoking {@link * #tryAcquire} until success. This method can be used * to implement method {@link Lock#lock}. *尝试以独占模式,获取锁,忽略中断。至少尝试一次,获取锁,成功则返回, 获取失败,添加到同步等待队列,可能重复的blocking and unblocking, 尝试获取锁,直到成功,用于lock方法 * @param arg the acquire argument. This value is conveyed to * {@link #tryAcquire} but is otherwise uninterpreted and * can represent anything you like. */ public final void acquire(int arg) { //如果获取锁失败,则添加独占模式节点,到队列中,自旋,队列头部节点尝试获取锁, 如果尝试获取失败,检查是否可以中断当前线程,如果可以,则中断当前线程。 if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } //待父类扩展 protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException(); }
先看
addWaiter(Node.EXCLUSIVE)
再看
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
最后再看
selfInterrupt();
//添加独占模式等待节点
addWaiter(Node.EXCLUSIVE)
/** * Creates and enqueues node for current thread and given mode. * * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared * @return the new node */ 创建独占或共享模式节点到同步等待队列中 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; }
再看
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
这个方法我们在Condition那篇文章中说过,
首次查看节点的前驱节点线程,是否是头节点,如果时,则尝试获取
锁,如果成功,则设置节点为头节点;否则检查当是否应该再获取锁的时候
,唤醒后继节点;如果尝试获取锁失败,则park当前线程,如果失败,则整个
过程失败,从队列中移除当前线程节点。
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); } }
自旋请求锁,如果可能的话挂起线程,直到得到锁,返回当前线程是否中断过
(如果park()过并且中断过的话有一个interrupted中断位)。
。acquireQueued过程是这样的:
1. 如果当前节点是AQS队列的头结点(如果第一个节点是DUMP节点也就是傀儡节点,
那么第二个节点实际上就是头结点了),就尝试在此获取锁tryAcquire(arg)。
如果成功就将头结点设置为当前节点(不管第一个结点是否是DUMP节点),返回中断位。否则进行2。
2. 检测当前节点是否应该park(),如果应该park()就挂起当前线程并且返回当前线程中断位。进行操作1。
最后再看
selfInterrupt(); /** * Convenience method to interrupt current thread. */ private static void selfInterrupt() { Thread.currentThread().interrupt(); }
再看公平锁
/** * Sync object for fair locks */ static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { //这个过程,前面说过//如果获取锁失败,则添加独占模式节点, 到队列中,自旋,队列头部节点尝试获取锁, 如果尝试获取失败,检查是否可以中断当前线程,如果可以,则中断当前线程。 acquire(1); } /** * Fair version of tryAcquire. Don't grant access unless * recursive call or no waiters or is first. */ 这个函数与SYNC的nonfairTryAcquire方法基本相同 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; } }
我们再回到SYNC的nonfairTryAcquire方法,非公平尝试获取锁;
//SYNC
/** * Performs non-fair tryLock. tryAcquire is * implemented in subclasses, but both need nonfair * try for trylock method. */ //在非公平锁的尝试获取锁方法中,会调用nonfairTryAcquire //acquires为尝试获取次数,一般为1 final boolean nonfairTryAcquire(int acquires) { //获取当前线程 final Thread current = Thread.currentThread(); int c = getState();//获取锁状态 if (c == 0) {//如果没有线程持有锁 if (compareAndSetState(0, acquires)) { //尝试获取锁,如果获取成功,则设置锁的持有者,为当前线程,返回ture setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { //如果锁被线程持有,判断持有者是不是当前线程; //如果当前线程是锁的持有者,则锁被当前线程持有的次数+获取次数acquires int nextc = c + acquires; if (nextc < 0) // overflow //如果锁被线程连续持有次数,小于0,则超出,一个线程可以连续持有锁的最大次数 //抛出异常 throw new Error("Maximum lock count exceeded"); //否则,设置锁状态,返回true setState(nextc); return true; } //锁被持有,且持有者非当前线程,返回false,获取锁失败。 return false; }
比较非公平锁的尝试获取锁nonfairTryAcquire与公平锁TryAcquire的区别在与
非公平尝试获取锁时,如果锁为打开状态,则锁住锁;而公平锁,则先看有没有前驱节点
,有前驱,则不能锁住锁,没有则可锁住。
我们再对比一下公平锁和非公平锁的lock方法
static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { //这个过程,前面说过 //如果获取锁失败,则添加独占模式节点, 到队列中,自旋,队列头部节点尝试获取锁,如果获取成功,设置当前节点为头节点; 如果尝试获取失败,检查是否可以中断当前线程,如果可以,则中断当前线程。 acquire(1); } } static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { //先以CAS方式获取锁,如果获取成功,设置当前线程为锁,持有者 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
从上面可以看出,非公平锁与公平锁lock的时候,最大的不同是非公平锁,
先以CAS的方式锁住锁,在进行acquire操作,而公平锁,直接acquire操作。
再来看可重入锁的其他方法
//ReentrantLock
/** * Acquires the lock. * * <p>Acquires the lock if it is not held by another thread and returns * immediately, setting the lock hold count to one. * 如果锁没有被其他线程锁持有,则立即返回,锁持有锁为1 * <p>If the current thread already holds the lock then the hold * count is incremented by one and the method returns immediately. *如果当前线程已经持有锁,则所持有锁自增1 * <p>If the lock is held by another thread then the * current thread becomes disabled for thread scheduling * purposes and lies dormant until the lock has been acquired, * at which time the lock hold count is set to one. */ 如果锁被其他线程所持有,则当前线程自旋,知道获取锁 public void lock() { //委托给同步器 sync.lock(); } /** * Acquires the lock only if it is not held by another thread at the time * of invocation. * 如果锁没有被其他线程所持有,则获取锁成功 * <p>Acquires the lock if it is not held by another thread and * returns immediately with the value {@code true}, setting the * lock hold count to one. Even when this lock has been set to use a * fair ordering policy, a call to {@code tryLock()} [i]will[/i] * immediately acquire the lock if it is available, whether or not * other threads are currently waiting for the lock. * This "barging" behavior can be useful in certain * circumstances, even though it breaks fairness. If you want to honor * the fairness setting for this lock, then use * {@link #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) } * which is almost equivalent (it also detects interruption). *如果锁没有被其他线程持有,则获取锁成功,立即返回true,锁持有数设为1. 当我们获取锁的策略为公平策略时,尝试获取锁时,如果锁可用,则获取成功, 无论其他线程和当前线程是否在等待锁。如果必须要保持公平可以用tryLock(long, TimeUnit) 方法。 * <p> If the current thread already holds this lock then the hold * count is incremented by one and the method returns {@code true}. * * <p>If the lock is held by another thread then this method will return * immediately with the value {@code false}. * * @return {@code true} if the lock was free and was acquired by the * current thread, or the lock was already held by the current * thread; and {@code false} otherwise */ //以非公平方式尝试获取锁 public boolean tryLock() { return sync.nonfairTryAcquire(1); } //以公平方式获取锁,其实公平方式,也不一定能保证绝对的公平,前面讲AQS说过 public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } /** * Acquires the lock unless the current thread is * {@linkplain Thread#interrupt interrupted}. *以可中断方式获取锁,当线程获取锁失败,则中断,当线程中断状态被消除时, 可以尝试获取锁。 * <p>Acquires the lock if it is not held by another thread and returns * immediately, setting the lock hold count to one. * 如果锁没有被其他线程锁持有,则立即返回,锁持有锁为1 * <p>If the current thread already holds this lock then the hold count * is incremented by one and the method returns immediately. *如果当前线程已经持有锁,则所持有锁自增1 * <p>If the lock is held by another thread then the * current thread becomes disabled for thread scheduling * purposes and lies dormant until one of two things happens: * * [list] 当锁被其他线程持有,则自旋,尝试获取锁,直到以下两种条件发生 * * <li>The lock is acquired by the current thread; or * 锁被当前线程获取 * <li>Some other thread {@linkplain Thread#interrupt interrupts} the * current thread. * 其他线程中断当前线程 * [/list] * * <p>If the lock is acquired by the current thread then the lock hold * count is set to one. * * <p>If the current thread: * * [list] * * <li>has its interrupted status set on entry to this method; or * * <li>is {@linkplain Thread#interrupt interrupted} while acquiring * the lock, * * [/list] * * then {@link InterruptedException} is thrown and the current thread's * interrupted status is cleared. * * <p>In this implementation, as this method is an explicit * interruption point, preference is given to responding to the * interrupt over normal or reentrant acquisition of the lock. * * @throws InterruptedException if the current thread is interrupted */ public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); }
//AQS
/** * Acquires in exclusive mode, aborting if interrupted. * Implemented by first checking interrupt status, then invoking * at least once {@link #tryAcquire}, returning on * success. Otherwise the thread is queued, possibly repeatedly * blocking and unblocking, invoking {@link #tryAcquire} * until success or the thread is interrupted. This method can be * used to implement method {@link Lock#lockInterruptibly}. * 以独占模式获取锁,如线程被中断,则aborting。 * @param arg the acquire argument. This value is conveyed to * {@link #tryAcquire} but is otherwise uninterpreted and * can represent anything you like. * @throws InterruptedException if the current thread is interrupted */ public final void acquireInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) //检查线程是否处于中断状态,是,则抛出中断异常 throw new InterruptedException(); if (!tryAcquire(arg)) //如果尝试获取锁,失败,则 doAcquireInterruptibly(arg); } /** * Acquires in exclusive interruptible mode. * @param arg the acquire argument */ private void doAcquireInterruptibly(int arg) throws InterruptedException { //添加独占模式节点,到同步等待队列 final Node node = addWaiter(Node.EXCLUSIVE); boolean failed = true; try { for (;;) { //以自旋方式,这个过程与acquireQueued相似 final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) throw new InterruptedException(); } } finally { if (failed) //如果失败,移除取消等待的线程节点。 cancelAcquire(node); } }
自旋请求锁,如果可能的话挂起线程,直到得到锁;在这一过程中,如果获取失败,且可park当前线程,则park当前线程,再判断是否可以中断,可以则抛出中断异常。
总结:
可重入自旋锁,当线程持有锁,可以多次获取锁,但最多只有2^31-1次;获取失败时,添加到同步等待队列自旋,直到获取锁成功;ReentrantLock关联一个同步锁SYNC,内部的SYNC是基于AQS实现的。同步锁SYNC有两种实现,公平锁与非公平锁;ReentrantLock默认创建的是非公平锁。比较非公平锁的尝试获取锁nonfairTryAcquire与公平锁TryAcquire的区别在于,非公平尝试获取锁时,如果锁为打开状态,则锁住锁;而公平锁,则先看有没有前驱节点,有前驱,则不能锁住锁,没有则可锁住。公平锁与公平锁lock,最大的不同是非公平锁,先以CAS的方式锁住锁,在进行acquire操作,而公平锁,直接acquire操作。
acquire操作主要过程为,自旋,检查节点的前驱节点是否为头节点,如果是,当前节点为同步队列的第一个节点,则尝试获取锁,如果成功,设置头结点为当前节点,否则判断尝试获取锁失败,是否应该park,如果需要park,则park当前线程,park后,检查是否可中断当前线程,如果可,则中断当前线程。
附:
发表评论
-
Executors解析
2017-04-07 14:38 1255ThreadPoolExecutor解析一(核心线程池数量、线 ... -
ScheduledThreadPoolExecutor解析三(关闭线程池)
2017-04-06 20:52 4455ScheduledThreadPoolExecutor解析一( ... -
ScheduledThreadPoolExecutor解析二(任务调度)
2017-04-06 12:56 2127ScheduledThreadPoolExecutor解析一( ... -
ScheduledThreadPoolExecutor解析一(调度任务,任务队列)
2017-04-04 22:59 4992Executor接口的定义:http://donald-dra ... -
ThreadPoolExecutor解析四(线程池关闭)
2017-04-03 23:02 9112Executor接口的定义:http: ... -
ThreadPoolExecutor解析三(线程池执行提交任务)
2017-04-03 12:06 6087Executor接口的定义:http://donald-dra ... -
ThreadPoolExecutor解析二(线程工厂、工作线程,拒绝策略等)
2017-04-01 17:12 3041Executor接口的定义:http://donald-dra ... -
ThreadPoolExecutor解析一(核心线程池数量、线程池状态等)
2017-03-31 22:01 20520Executor接口的定义:http://donald-dra ... -
ScheduledExecutorService接口定义
2017-03-29 12:53 1511Executor接口的定义:http://donald-dra ... -
AbstractExecutorService解析
2017-03-29 08:27 1081Executor接口的定义:http: ... -
ExecutorCompletionService解析
2017-03-28 14:27 1595Executor接口的定义:http://donald-dra ... -
CompletionService接口定义
2017-03-28 12:39 1068Executor接口的定义:http://donald-dra ... -
FutureTask解析
2017-03-27 12:59 1329package java.util.concurrent; ... -
Future接口定义
2017-03-26 09:40 1198/* * Written by Doug Lea with ... -
ExecutorService接口定义
2017-03-25 22:14 1164Executor接口的定义:http://donald-dra ... -
Executor接口的定义
2017-03-24 23:24 1677package java.util.concurrent; ... -
简单测试线程池拒绝执行任务策略
2017-03-24 22:37 2031线程池多余任务的拒绝执行策略有四中,分别是直接丢弃任务Disc ... -
JAVA集合类简单综述
2017-03-23 22:51 925Queue接口定义:http://donald-draper. ... -
DelayQueue解析
2017-03-23 11:00 1737Queue接口定义:http://donald-draper. ... -
SynchronousQueue解析下-TransferQueue
2017-03-22 22:20 2140Queue接口定义:http://donald-draper. ...
相关推荐
相较于`synchronized`,`ReentrantLock`的主要优势在于其灵活性、可重入性和可中断性。 1. **可重入性**: 无论是`synchronized`还是`ReentrantLock`,都支持可重入特性。这意味着一个线程可以多次获取同一锁,...
Java中的ReentrantLock是Java并发包(java.util.concurrent.locks)中的一个高级锁,它是可重入的,意味着一个线程可以多次获取同一锁。在深入ReentrantLock之前,我们首先需要了解Java并发编程的基础,特别是Java...
ReentrantLock,可重入锁,是Java并发编程中一个重要的锁实现,它提供了比synchronized更高级别的控制能力,包括公平性和非公平性选择。本文将深入探讨ReentrantLock的原理,特别是其公平锁与非公平锁的概念,以及...
5. 可重入锁:ReentrantLock 锁支持可重入锁机制,允许线程多次获得锁。 三、Volatile 原理 1. volatile 关键字:volatile 关键字用于声明变量,可以确保变量的可见性和禁止指令重排。 2. volatile 的应用:...
ReentrantLock的可重入性是指一个线程获取锁之后再尝试获取锁时会自动获取锁。ReentrantLock的可重入性是通过继承AQS实现的。ReentrantLock的可重入性使得其可以在实际编程中使用频率很高。 ReentrantLock是一种...
ReentrantLock 是 Java 中的一种常用锁机制,它提供了一个可重入的锁机制,能够确保线程安全。下面我们将详细介绍 ReentrantLock 的使用和实现原理。 一、ReentrantLock 的构造方法 ReentrantLock 提供了两个构造...
Java中的显示锁ReentrantLock使用与原理详解 Java中的显示锁ReentrantLock是Java concurrency API中的一种同步机制,用于解决多线程安全问题。ReentrantLock是Java 5中引入的,它是一种可重入锁,允许同一个线程多...
并通过源码解读,阐述了线程如何获取和释放锁的具体流程。 适合人群:具有一定的Java编程基础,对并发编程感兴趣的软件开发人员。 使用场景及目标:适用于需要深入了解Java并发控制机制,特别是希望在实际项目中选择...
Java多线程ReentrantLock互斥锁详解 ReentrantLock是Java多线程编程中的一种锁机制,它可以实现线程之间的同步访问资源。ReentrantLock的主要特点是可以重入,即一个线程可以多次获得锁,而不需要释放锁。这种机制...
ReentrantLock源码详解--条件锁 ReentrantLock源码详解中最重要的一个部分就是条件锁,条件锁是指在获取锁之后发现当前业务场景自己无法处理,而需要等待某个条件的出现才可以继续处理时使用的一种锁。今天我们来...
1. **可重入性**:ReentrantLock允许一个线程在已经获取锁的情况下再次获取该锁,而不会发生死锁。这对于递归方法或者嵌套同步块特别有用。例如,当一个线程已经获得了锁,然后在同步代码块内部调用了另一个需要相同...
ReentrantLock 的实现原理基于 AQS(AbstractQueuedSynchronizer),是一个重入锁,允许一个线程反复地获取锁而不会出现自己阻塞自己的情况。 ReentrantLock 的构造方法可以指定锁的类型,包括公平锁和非公平锁。...
- **ReentrantLock**:是Lock接口的实现,具备可重入特性,即同一线程可多次获取同一把锁,这对于递归或嵌套调用非常有用。 3. **AQS(AbstractQueuedSynchronizer)** - **AQS简介**:AQS是实现锁和同步器的...
显示锁的一个重要接口是Lock,它提供了对锁操作的更细粒度控制,而ReentrantLock是Lock的一个具体实现,它提供了可重入的特性,允许线程多次进入锁定的代码块。 Lock接口主要定义了以下方法: 1. lock():获取锁,...
ReentrantLock 是一种可重入锁,意味着同一个线程可以多次获得锁,而不会造成死锁。 ReentrantLock 的主要方法有: 1. lock():获得锁,如果锁已被占用,则等待 2. lockInterruptibly():获得锁,但有限响应中断 3...
`Lock`接口提供了比`synchronized`更高级别的锁控制,它支持更复杂的同步模式,如可重入、公平性、尝试获取锁以及中断锁等待等功能。`ReentrantLock`是`Lock`接口的一个实现,它允许一个线程多次进入同一锁保护的...
ReentrantLock的主要特点是支持可重入性,即一个线程可以多次获取同一锁,每次获取都会增加一个获取计数,只有当计数归零时,锁才会真正释放。 1. 可重入锁的原理 可重入锁允许持有锁的线程再次获取该锁而不会发生...
AQS是J.U.C包下AbstractQueuedSynchronizer抽象的队列式的同步器的简称,这是一个抽象类,它定义了一套多线程访问共享资源的同步器框架,J.U.C包下的许多同步类实现都依赖于它,比如ReentrantLock/Semaphore/...