Contents

二进制信号量与重入锁

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. 死锁恢复

二进制信号量提供了一种非所有权释放机制。因此,任何线程都可以释放二进制信号量的死锁恢复许可。

相反,在可重入锁的情况下,很难实现死锁恢复。例如,如果可重入锁的所有者线程进入休眠或无限等待,则无法释放资源,从而导致死锁情况。