Answers:
信号量可以计数,而互斥量只能计数为1。
假设您正在运行一个接受客户端连接的线程。该线程可以同时处理10个客户端。然后,每个新客户端将信号量设置为达到10。当信号量具有10个标志时,您的线程将不接受新连接
互斥锁通常用于保护物品。假设您的10个客户端可以访问系统的多个部分。然后,您可以使用互斥锁保护系统的一部分,因此当1个客户端连接到该子系统时,其他任何人都不能访问。您也可以为此使用信号量。互斥锁是“互斥信号量”。
ReentrantLock
。所有这些都是递归的。我不知道任何非递归互斥体的“实际”示例(我仅在教科书中看到过它们),因此我没有考虑它们。
不幸的是,每个人都错过了信号量和互斥量之间最重要的区别。“ 所有权 ” 的概念。
信号量没有所有权的概念,这意味着任何线程都可以释放信号量(这本身可能导致很多问题,但可以帮助“死亡检测”)。互斥锁确实具有所有权的概念(即,您只能释放已获取的互斥锁)。
所有权对于并发系统的安全编程非常重要。我总是建议您优先使用互斥锁而不是信号量(但会影响性能)。
互斥对象还可以支持优先级继承(可以帮助解决优先级倒置问题)和递归(消除一种类型的死锁)。
还应该指出的是,存在“二进制”信号量和“计数/通用”信号量。Java的信号量是一个计数信号量,因此允许使用大于1的值对其进行初始化(而正如所指出的,互斥量只能在概念上计数为1)。其他职位也指出了这一点的用处。
综上所述,除非您有多个资源要管理,否则我总是建议在信号量上使用互斥量。
信号量:
计数信号量。从概念上讲,信号量维护一组许可证。
acquire()
如果需要,每个块都会阻塞,直到获得许可为止,然后再获得许可。每个都release()
添加一个许可证,有可能释放阻止收购方。但是,没有使用实际的许可对象。信号量只是保持可用数量的计数并采取相应措施。
与无法访问某些(物理或逻辑)资源相比,信号量通常用于限制线程数
Java没有内置的Mutex API。但是可以将其实现为二进制信号量。
初始化为一个的信号量可以被用作互斥锁,该信号量最多只能使用一个许可。这通常被称为二进制信号量,因为它只有两种状态:一个许可可用,或者零许可可用。
以这种方式使用时,二进制信号量具有属性(与许多Lock实现不同),该“锁”可以由所有者以外的线程释放(因为信号量没有所有权概念)。这在某些特殊情况下(例如死锁恢复)很有用。
因此,信号量和互斥量之间的主要区别是:
信号量限制线程通过许可访问资源的数量。Mutex仅允许一个线程访问资源。
没有线程拥有信号量。线程可以通过调用acquire()
和release()
方法来更新许可数量。互斥锁只能由持有锁的线程来解锁。
当互斥锁与条件变量一起使用时,会出现一个括号,即很明显,程序的哪一部分正在被保护。信号量不一定是这种情况,可以将其称为并发编程。它功能强大,但以非结构化,不确定的方式易于使用。
同步对象 信号量实现经典的交通信号灯。交通信号灯控制对计数器共享资源的访问。如果计数器大于零,则授予访问权限。如果为零,则拒绝访问。计数器计算允许访问共享资源的权限。然后,要访问资源,线程必须从交通信号灯接收许可。通常,要使用交通信号灯,想要访问共享资源的线程会尝试获取许可。如果交通信号灯计数大于零,则线程获取许可,并且交通信号灯计数递减。否则,线程将被锁定,直到获得许可为止。当线程不再需要访问共享资源时,它会释放权限,因此交通信号灯计数会增加。如果还有另一个线程正在等待许可,它当时获得了许可证。Java的Semaphore类实现了此机制。
信号量具有两个生成器:
Semaphore(int num)
Semaphore(int num, boolean come)
num指定许可的初始计数。然后num指定在给定时间可以访问共享资源的线程数。如果num为1,则它可以一次访问一个线程的资源。通过设置都为真,你能保证你正在等待线程获准在他们要求的顺序。
您可以比较无与伦比的信号,从技术上讲,信号量和互斥量之间没有区别,这是没有意义的。Mutex只是一个有意义的名称,就像您的应用程序逻辑中的任何名称一样,它意味着您将信号量初始化为“ 1”,通常用于保护资源或受保护的变量以确保互斥。