二进制信号量与重入锁
1. 概述
在本教程中,我们将探讨二进制信号量和可重入锁。此外,我们会将它们相互比较,看看哪一个最适合常见情况。
2. 什么是二进制信号量?
二进制信号量 为访问单个资源提供了一种信令机制。换句话说,二进制信号量提供了一种互斥机制,一次只允许一个线程访问临界区。
为此,它只保留一个可供访问的许可证。因此,二进制信号量只有两种状态:一个许可可用或零个许可可用。 让我们讨论一个使用Java 中可用的Semaphore 类的二进制信号量 的简单实现:
Semaphore binarySemaphore = new Semaphore(1);
try {
binarySemaphore.acquire();
assertEquals(0, binarySemaphore.availablePermits());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
binarySemaphore.release();
assertEquals(1, binarySemaphore.availablePermits());
}
在这里,我们可以观察到,acquire方法将可用许可减一。类似地,release方法将可用许可证增加一。
此外,Semaphore类提供了acquire参数。当设置为true时,fairness参数确保请求线程获得许可的顺序(基于它们的等待时间):
Semaphore binarySemaphore = new Semaphore(1, true);
3. 什么是可重入锁?
重入锁是一种互斥机制 ,它允许线程重新进入资源上的锁(多次)而不会出现死锁情况。
进入锁的线程每次将保持计数增加一。同样,当请求解锁时,保持计数会减少。因此,资源被锁定直到计数器归零。
例如,让我们看一个使用Java 中可用的ReentrantLock 类的简单实现:
ReentrantLock reentrantLock = new ReentrantLock();
try {
reentrantLock.lock();
assertEquals(1, reentrantLock.getHoldCount());
assertEquals(true, reentrantLock.isLocked());
} finally {
reentrantLock.unlock();
assertEquals(0, reentrantLock.getHoldCount());
assertEquals(false, reentrantLock.isLocked());
}
在这里,lock方法将保持计数增加一并锁定资源。类似地,如果保持计数为零,unlock方法会减少保持计数并解锁资源。
当一个线程重新进入锁时,它必须请求解锁相同的次数才能释放资源:
reentrantLock.lock();
reentrantLock.lock();
assertEquals(2, reentrantLock.getHoldCount());
assertEquals(true, reentrantLock.isLocked());
reentrantLock.unlock();
assertEquals(1, reentrantLock.getHoldCount());
assertEquals(true, reentrantLock.isLocked());
reentrantLock.unlock();
assertEquals(0, reentrantLock.getHoldCount());
assertEquals(false, reentrantLock.isLocked());
与Semaphore类类似,ReentrantLock类也支持fairness参数:
ReentrantLock reentrantLock = new ReentrantLock(true);
4. 二进制信号量与可重入锁
4.1. 机制
二进制信号量是一种信号机制,而可重入锁是一种锁定机制。
4.2. 所有权
没有线程是二进制信号量的所有者。但是,最后一个成功锁定资源的线程是可重入锁的所有者。
4.3. 自然
二进制信号量本质上是不可重入的,这意味着同一个线程不能重新获取临界区,否则会导致死锁情况。
另一方面,可重入锁本质上允许同一线程多次重新进入锁。
4.4. 灵活性
二进制信号量通过允许自定义实现锁定机制和死锁恢复来**提供更高级别的同步机制。**因此,它为开发人员提供了更多控制权。
但是,可重入锁是具有固定锁定机制的低级同步。
4.5. 修改
二进制信号量支持诸如等待和信号之类的操作(在 Java 的Semaphore类的情况下为获取和释放),以允许任何进程修改可用的许可。
另一方面,只有锁定/解锁资源的同一线程才能修改可重入锁。
4.6. 死锁恢复
二进制信号量提供了一种非所有权释放机制。因此,任何线程都可以释放二进制信号量的死锁恢复许可。
相反,在可重入锁的情况下,很难实现死锁恢复。例如,如果可重入锁的所有者线程进入休眠或无限等待,则无法释放资源,从而导致死锁情况。