斜体为抽象类,下横线为接口
Совокупная сводка отношений:
- ReentrantLock реализует интерфейс Lock, Serializable.
- ReentrantLock.Sync (внутренний класс) наследует AQS
- ReentrantLock.NonfairSync и ReentrantLock.FairSync наследуют ReentrantLock.Sync
- ReentrantLock содержит объект ReentrantLock.Sync (реализующий функцию блокировки)
Сводка реализации блокировки:
- Синхронная очередь состоит из узлов Node (имеются два указателя «голова» и «хвост» иhead инициализируется пустым узлом)
- Состояние int отмечает количество используемых блокировок (обычно 1 для эксклюзивных блокировок, >1 при повторном входе)
- Добавить в конец очереди при блокировке()
- При разблокировке () отпустите головной узел и укажите на следующий узел head=head.next, затем разбудите текущий головной узел
природа:
- Эксклюзивная блокировка (исключительная блокировка): только один поток может получить блокировку
- Повторно входящие блокировки: поток может блокировать() несколько раз
- Справедливая/несправедливая блокировка: только для процесса блокировки
- Несправедливая блокировка: попытайтесь получить блокировку, если она возвращается немедленно, если это не удается, она присоединяется к очереди синхронизации
- Справедливая блокировка: напрямую присоединяйтесь к очереди синхронизации
Lock
Интерфейс блокировки определяет поведение блокировки.
public interface Lock {
//上锁(不响应Thread.interrupt()直到获取锁)
void lock();
//上锁(响应Thread.interrupt())
void lockInterruptibly() throws InterruptedException;
//尝试获取锁(以nonFair方式获取锁)
boolean tryLock();
//在指定时间内尝试获取锁(响应Thread.interrupt(),支持公平/二阶段非公平)
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
//解锁
void unlock();
//获取Condition
Condition newCondition();
}
процесс блокировки()
//锁具体实现
private final Sync sync;
//根据传入参数选择FairSync或NonfairSync实现
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
public void lock() {
sync.lock();
}
#java.util.concurrent.locks.ReentrantLock.Sync
abstract void lock();
честный замок
Присоединяйтесь к очереди синхронизации (блокировка будет получена сразу, когда очередь синхронизации пуста), дождитесь блокировки
#java.util.concurrent.locks.ReentrantLock.FairSync
final void lock() {
acquire(1);
}
#java.util.concurrent.locks.AbstractQueuedSynchronizer
public final void acquire(int arg) {
if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
процесс приобретения():
-
tryAcquire(): метод шаблона, получение блокировки
#java.util.concurrent.locks.ReentrantLock.FairSync protected final boolean tryAcquire(int acquires) { //获取当前线程 final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) {//当前锁没被占用 if (!hasQueuedPredecessors() &&//1.判断同步队列中是否有节点在等待 compareAndSetState(0, acquires)) {//2.如果上面!1成立,修改state值(表明当前锁已被占用) setExclusiveOwnerThread(current);//3.如果2成立,修改当前占用锁的线程为当前线程 return true; } } else if (current == getExclusiveOwnerThread()) {//占用锁线程==当前线程(重入) int nextc = c + acquires;// if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc);//修改status return true; } return false;//直接获取锁失败 } -
AcquireQueued(addWaiter(Node.EXCLUSIVE), arg): присоединиться к очереди синхронизации
#java.util.concurrent.locks.AbstractQueuedSynchronizer //1 private Node addWaiter(Node mode) { //生成node Node node = new Node(Thread.currentThread(), mode); Node pred = tail; if (pred != null) { //将node加到队列尾部 node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } //如果加入失败(多线程竞争或者tail指针为null) enq(node); return node; } //1.1 private Node enq(final Node node) { //死循环加入节点(cas会失败) for (;;) { Node t = tail; if (t == null) { //tail为null,同步队列初始化 //设置head指针 if (compareAndSetHead(new Node()))//注意这里是个空节点!! tail = head;//将tail也指向head } else { node.prev = t;//将当前node加到队尾 if (compareAndSetTail(t, node)) { t.next = node; return t;//注意这里才返回 } } } } //2 final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { //表示是否被打断 boolean interrupted = false; for (;;) { //获取node.pre节点 final Node p = node.predecessor(); if (p == head //当前节点是否是同步队列中的第二个节点 && tryAcquire(arg)) {//获取锁,head指向当前节点 setHead(node);//head=head.next p.next = null;//置空 failed = false; return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && //是否空转(因为空转唤醒是个耗时操作,进入空转前判断pre节点状态.如果pre节点即将释放锁,则不进入空转) parkAndCheckInterrupt())//利用unsafe.park()进行空转(阻塞) interrupted = true;//如果Thread.interrupt()被调用,(不会真的被打断,会继续循环空转直到获取到锁) } } finally { if (failed)//tryAcquire()过程出现异常导致获取锁失败,则移除当前节点 cancelAcquire(node); } }Краткое описание процесса:
- Бездействие (если текущий узел является вторым узлом в очереди синхронизации, он напрямую получит блокировку и вернется)
- получить замок
注意:这里有两次tryAcquire()过程.第一次,为了避免同步队列为空时还插入队列产生的性能耗费(cas空转).第二次,就是正常的流程.先插入队尾,然后等待唤醒,再获取锁 -
selfInterrupt(): разбудить текущий поток
static void selfInterrupt() {//在获取锁之后 响应intterpt()请求 Thread.currentThread().interrupt(); }
несправедливый замок
первый этап
#java.util.concurrent.locks.ReentrantLock.NonfairSync
final void lock() {
//在acquire()之前先尝试获取锁
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
второй этап Процесс Acquire() точно такой же, как и для честной блокировки, с той лишь разницей, что реализована функция tryAcquire().
#java.util.concurrent.locks.ReentrantLock.NonfairSync
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
#java.util.concurrent.locks.ReentrantLock.Sync
final boolean nonfairTryAcquire(int acquires) {//这个过程其实和FairSync.tryAcquire()基本一致
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;
}
| разница | процесс lock() (один этап) | Процесс tryAcquire() (два этапа) |
|---|---|---|
| FairSync | непосредственно приобретать () | Если ни один поток в настоящее время не удерживает блокировку, если очередь синхронизации пуста, получить блокировку |
| NonFairSync | Сначала попробуйте получить блокировку, а затем получите() | Если ни один поток в настоящее время не удерживает блокировку, получить блокировку |
процесс разблокировки()
#java.util.concurrent.locks.ReentrantLock
public void unlock() {
sync.release(1);
}
#java.util.concurrent.locks.AbstractQueuedSynchronizer
public final boolean release(int arg) {
if (tryRelease(arg)) {//释放锁
Node h = head;
if (h != null &&//head节点为空(非公平锁直接获取锁)
h.waitStatus != 0)
unparkSuccessor(h);//唤醒同步队列中离head最近的一个waitStatus<=0的节点
return true;
}
return false;
}
#java.util.concurrent.locks.ReentrantLock
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
//持有锁的线程==当前线程
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {//重入锁全部释放
free = true;
//置空持有锁线程
setExclusiveOwnerThread(null);
}
//state==0(此时持有锁,不用cas)
setState(c);
return free;
}
процедура lockInterruptably()
lockInterruptably() в основном такой же, как lock(), разница в том, что Thread.intterpt() отвечает по-разному.
//lock()
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
//表示是否被打断
boolean interrupted = false;
for (;;) {
//获取node.pre节点
final Node p = node.predecessor();
if (p == head //当前节点是否是同步队列中的第二个节点
&& tryAcquire(arg)) {//获取锁,当前head指向当前节点
setHead(node);//head=head.next
p.next = null;//置空
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) && //是否空转(因为空转唤醒是个耗时操作,进入空转前判断pre节点状态.如果pre节点即将释放锁,则不进入空转)
parkAndCheckInterrupt())//利用unsafe.park()进行空转(阻塞)
interrupted = true;//如果Thread.interrupt()被调用,(不会真的被打断,会继续循环空转直到获取到锁)
}
} finally {
if (failed)//tryAcquire()过程出现异常导致获取锁失败,则移除当前节点
cancelAcquire(node);
}
}
// lockInterruptibly()
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null;
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())//唯一区别当Thread.intterpt()打断时,直接抛出异常
throw new InterruptedException();
}
} finally {
if (failed)//然后移除当前节点
cancelAcquire(node);
}
}
tryLock()
#java.util.concurrent.locks.ReentrantLock
public boolean tryLock() {
//尝试获取非公平锁
return sync.nonfairTryAcquire(1);
}
tryLock(long timeout, TimeUnit unit)
#java.util.concurrent.locks.ReentrantLock
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
#java.util.concurrent.locks.AbstractQueuedSynchronizer
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||//获取锁(公平/非公平)
doAcquireNanos(arg, nanosTimeout);//在指定时间内等待锁(空转)
}
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
...
final long deadline = System.nanoTime() + nanosTimeout;
//加入队尾
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null;
failed = false;
return true;
}
//上面与acquireQueued()相同,重点看这里
//计算剩余时间
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L)
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
//利用parkNanos()指定空转时间
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())//如果被Thread.interrupt(),则抛异常
throw new InterruptedException();
}
} finally {
if (failed)//移除节点
cancelAcquire(node);
}
}
newCondition()
public Condition newCondition() {
return sync.newCondition();
}
#java.util.concurrent.locks.ReentrantLock.Sync
final ConditionObject newCondition() {
return new ConditionObject();
}