当我们已经锁定可重入锁时,再次锁定可重入锁有何帮助?
how does locking a reentrant lock again helps when we already have the lock on it?
因此,如果当前线程再次获取锁,可重入锁会将计数递增 1。我无法理解的是为什么以及如何帮助或有益于我们?
可重入锁这样做的原因是为了不再锁定已经获得此锁的同一个线程。
例如:假设您有线程 A 正在获取可重入锁 A。然后线程 B 尝试获取锁 A,这将导致线程 B 被阻塞(有关线程状态的更多信息,请参见 here).现在,线程 A 正在尝试(再次)获取锁 A。
因为重入锁现在增加了它的计数,所以线程 A 没有被阻塞。线程 A 仍然可以访问锁并可以继续(锁存储有关深度的信息)。如果他(迟早)释放锁,计数将再次降低,以检查线程 A 是否仍然需要锁。如果计数为0,意味着线程A每获得一次就释放一次,线程B将获得对锁的访问。
如果没有重入,您现在将拥有 deadlock。为什么?因为线程 A 有锁并且会等待再次获得它。
并发性可能非常复杂,reentrancy 有助于(只是一点点)降低这种复杂性。
当您想调用另一个也需要锁的方法时,这有助于解决异常情况。
ReentrantLock lock = new ReentrantLock();
public void doSomething() {
lock.lock();
try {
// Something.
} finally {
lock.unlock();
}
}
public void somethingElse () {
lock.lock();
try {
// Something else.
// We can now call another locking method without risking my lock being released.
doSomething();
} finally {
lock.unlock();
}
}
这里public可以调用doSomething
,它会获取锁,执行它的事情然后在调用unlock
时释放锁。
然而,当调用 somethingElse
并且它调用 doSomething
时,它只会增加锁定计数。当 doSomething
解锁时 不释放锁 ,它只是倒计时锁计数,将最后的解锁留在 somethingElse
以释放锁。
增加锁计数的目的是跟踪线程获得锁的次数,这样直到线程指示准备释放相同次数的锁时才会真正释放锁的次数。
假设锁定命令将与释放锁定的命令相匹配。
假设我的代码进入了需要锁的代码段A。
然后不退出代码段 A,它进入代码段 B,也需要相同的锁。正如您所注意到的,我们有锁,所以我们不需要阻塞。
但是我们会离开B段,B段写的是退出时释放锁。 (否则在没有锁定的情况下到达 B 部分的代码将永远不会释放锁定。)
不过,我们仍在 A 部分,所以我们不想真的放弃锁,否则其他线程可能会在我们进入时占用它A 部分
所以当我们进入 B 部分时,我们增加了锁定计数,这意味着当我们退出 B 部分时,我们可以将计数减一,看到它没有回到 0,而不是释放它。
然后当A部分再次释放锁时,计数回落到0并且那是我们真正释放锁的时候。
因此,如果当前线程再次获取锁,可重入锁会将计数递增 1。我无法理解的是为什么以及如何帮助或有益于我们?
可重入锁这样做的原因是为了不再锁定已经获得此锁的同一个线程。
例如:假设您有线程 A 正在获取可重入锁 A。然后线程 B 尝试获取锁 A,这将导致线程 B 被阻塞(有关线程状态的更多信息,请参见 here).现在,线程 A 正在尝试(再次)获取锁 A。
因为重入锁现在增加了它的计数,所以线程 A 没有被阻塞。线程 A 仍然可以访问锁并可以继续(锁存储有关深度的信息)。如果他(迟早)释放锁,计数将再次降低,以检查线程 A 是否仍然需要锁。如果计数为0,意味着线程A每获得一次就释放一次,线程B将获得对锁的访问。
如果没有重入,您现在将拥有 deadlock。为什么?因为线程 A 有锁并且会等待再次获得它。
并发性可能非常复杂,reentrancy 有助于(只是一点点)降低这种复杂性。
当您想调用另一个也需要锁的方法时,这有助于解决异常情况。
ReentrantLock lock = new ReentrantLock();
public void doSomething() {
lock.lock();
try {
// Something.
} finally {
lock.unlock();
}
}
public void somethingElse () {
lock.lock();
try {
// Something else.
// We can now call another locking method without risking my lock being released.
doSomething();
} finally {
lock.unlock();
}
}
这里public可以调用doSomething
,它会获取锁,执行它的事情然后在调用unlock
时释放锁。
然而,当调用 somethingElse
并且它调用 doSomething
时,它只会增加锁定计数。当 doSomething
解锁时 不释放锁 ,它只是倒计时锁计数,将最后的解锁留在 somethingElse
以释放锁。
增加锁计数的目的是跟踪线程获得锁的次数,这样直到线程指示准备释放相同次数的锁时才会真正释放锁的次数。
假设锁定命令将与释放锁定的命令相匹配。
假设我的代码进入了需要锁的代码段A。
然后不退出代码段 A,它进入代码段 B,也需要相同的锁。正如您所注意到的,我们有锁,所以我们不需要阻塞。
但是我们会离开B段,B段写的是退出时释放锁。 (否则在没有锁定的情况下到达 B 部分的代码将永远不会释放锁定。)
不过,我们仍在 A 部分,所以我们不想真的放弃锁,否则其他线程可能会在我们进入时占用它A 部分
所以当我们进入 B 部分时,我们增加了锁定计数,这意味着当我们退出 B 部分时,我们可以将计数减一,看到它没有回到 0,而不是释放它。
然后当A部分再次释放锁时,计数回落到0并且那是我们真正释放锁的时候。