Java 中的互斥量和信号量是啥?主要区别是啥?

Posted

技术标签:

【中文标题】Java 中的互斥量和信号量是啥?主要区别是啥?【英文标题】:What is mutex and semaphore in Java ? What is the main difference?Java 中的互斥量和信号量是什么?主要区别是什么? 【发布时间】:2010-10-20 18:11:18 【问题描述】:

什么是 Java 中的互斥量和信号量?主要区别是什么?

【问题讨论】:

***.com/questions/4039899/…中的类似查询 【参考方案1】:

不幸的是,每个人都忽略了信号量和互斥量之间最重要的区别; “所有权”的概念。

信号量没有所有权的概念,这意味着任何线程都可以释放一个信号量(这本身会导致许多问题,但有助于“死亡检测”)。而互斥体确实具有所有权的概念(即您只能释放已获得的互斥体)。 所有权对于并发系统的安全编程非常重要。我总是建议使用互斥锁而不是信号量(但会影响性能)。

互斥体还可以支持优先级继承(这有助于解决优先级反转问题)和递归(消除一种死锁)。

还应该指出,存在“二进制”信号量和“计数/通用”信号量。 Java 的信号量是一个计数信号量,因此允许使用大于一的值对其进行初始化(然而,正如所指出的,互斥量只能在概念上计数为一)。其他帖子中已经指出了这一点的用处。

总而言之,除非您要管理多个资源,否则我总是推荐互斥体而不是信号量。

【讨论】:

Feabhas 的回答非常重要——互斥锁检查试图释放互斥锁的线程实际上拥有它。我有这个作为面试问题,所以值得尝试记住它。【参考方案2】:

信号量可以计数,而互斥量只能计数到1。

假设您正在运行一个接受客户端连接的线程。该线程可以同时处理 10 个客户端。然后每个新客户端设置信号量直到达到 10。当信号量有 10 个标志时,您的线程将不会接受新连接

互斥锁通常用于保护东西。假设您的 10 个客户端可以访问系统的多个部分。然后,您可以使用互斥锁保护系统的一部分,因此当 1 个客户端连接到该子系统时,其他任何人都不应访问。您也可以为此目的使用信号量。互斥体是"Mutual Exclusion Semaphore"。

【讨论】:

这并不完全正确。同一个线程可以多次进入同一个互斥体,所以需要维护一个计数来确保入口和出口是平衡的。 @finnw,通常有两种类型的互斥锁,递归和非递归。 Java默认使用递归类型吗? @edA-qa mort-ora-y,Java VM 或 API 规范中没有使用术语“Mutex”,所以我假设它指的是内置在每个对象中的监视器,这也是类似于称为 Mutex 的 Win32 对象。这同样适用于ReentrantLock。所有这些都是递归的。我不知道非递归互斥锁的任何“现实世界”示例(我只在教科书中看到过)所以我没有考虑它们。 可以使用计数为 1 的信号量来实现非递归互斥锁。如果您想防止递归调用,这可能很有用。这有实际用途,我个人在大型项目中使用它来检测初始化代码中的循环(A初始化B,它试图再次初始化A)。 在 C++11 (C++0x) 标准中,互斥锁是非递归的。他们还为需要的人提供了一个单独的“recursive_mutex”。我知道我们在这里谈论的是 Java,但是现在我们中的许多人都在跨语言编写代码。【参考方案3】:

Mutex 基本上是互斥的。一次只能有一个线程获取资源。当一个线程获取资源时,在拥有该资源的线程释放之前,不允许其他线程获取该资源。所有等待获取资源的线程都会被阻塞。

信号量用于控制执行的线程数。将有固定的资源集。每次线程拥有相同资源时,资源计数都会减少。当信号量计数达到 0 时,则不允许其他线程获取资源。线程被阻塞,直到拥有资源的其他线程释放。

简而言之,主要区别在于一次允许多少个线程获取资源?

Mutex -- 其 ONE。 信号量 -- 它的 DEFINED_COUNT,(与信号量数量一样多)

【讨论】:

【参考方案4】:

互斥锁用于对资源的串行访问,而信号量则将对资源的访问限制为设定的数量。您可以将互斥锁视为访问计数为 1 的信号量。无论您将信号量计数设置为多少,线程都可以在资源被阻塞之前访问该资源。

【讨论】:

【参考方案5】:

信号量是一种计数同步机制,互斥体不是。

【讨论】:

【参考方案6】:

互斥量通常被称为二进制信号量。虽然可以使用任何非零计数创建信号量,但互斥锁在概念上是一个上限计数为 1 的信号量。

【讨论】:

【参考方案7】:

这个问题有相关答案和官方Java指导链接:Is there a Mutex in Java?

【讨论】:

【参考方案8】:

Semaphore:

计数信号量。从概念上讲,信号量维护一组许可。如有必要,每个acquire() 都会阻塞,直到获得许可,然后再接受它。每个release() 添加一个许可,可能会释放一个阻塞的收购方。但是,没有使用实际的许可对象; Semaphore 只是对可用数量进行计数并采取相应措施。

信号量通常用于限制可以访问某些(物理或逻辑)资源的线程数

Java 没有内置的 Mutex API。但它可以实现为二进制信号量。

初始化为 1 的信号量,并且使用时最多只有一个可用的许可,可以用作互斥锁。这通常被称为二进制信号量,因为它只有两种状态:一个许可可用,或零个许可可用。

当以这种方式使用时,二进制信号量具有属性(与许多 Lock 实现不同),“锁”可以由所有者以外的线程释放(因为信号量没有所有权的概念)。这在某些特殊情况下很有用,例如死锁恢复。

所以key differences 在 Semaphore 和 Mutex 之间:

    信号量限制通过许可访问资源的线程数。互斥锁只允许一个线程访问资源。

    没有线程拥有信号量。线程可以通过调用acquire()release() 方法来更新许可数量。互斥锁只能由持有锁的线程解锁。

    当互斥体与条件变量一起使用时,有一个隐含的括号——很明显程序的哪一部分受到保护d。信号量不一定是这种情况,它可能被称为并发编程的go to——它功能强大但太容易以非结构化、不确定的方式使用。

【讨论】:

【参考方案9】:

互斥量是二进制信号量。它必须用 1 初始化,以便满足先到先服务原则。这给我们带来了每个互斥体的另一个特殊属性:执行down的人,一定是执行up的人。因此,我们在某些资源上获得了互斥。

现在您可以看到互斥锁是一般信号量的一个特例。

【讨论】:

【参考方案10】:

同步对象信号量实现了一个经典的红绿灯。红绿灯控制对计数器共享资源的访问。如果计数器大于零,则授予访问权限;如果为零,则拒绝访问。计数器计算允许访问共享资源的权限。然后,要访问资源,线程必须从红绿灯处获得许可。通常,要使用红绿灯,想要访问共享资源的线程会尝试获取许可。如果红绿灯计数大于零,则线程获得许可,并且红绿灯计数递减。否则线程将被锁定,直到它获得许可。当线程不再需要访问共享资源时,它会释放权限,从而增加红绿灯计数。如果有另一个线程在等待一个许可,它会在那个时候获得一个许可。 Java 的 Semaphore 类实现了这种机制。

Semaphore 有两个构建器:

Semaphore(int num)
Semaphore(int num, boolean come)

num 指定许可的初始计数。然后 num 指定在给定时间可以访问共享资源的线程数。如果 num 为 1,它可以一次访问一个线程的资源。通过将 come 设置为 true,您可以保证您正在等待的线程按照它们请求的顺序被授予权限。

【讨论】:

【参考方案11】:

你比较的无以伦比,技术上没有区别的信号量和互斥量没有意义。 互斥锁只是一个重要的名称,就像您的应用程序逻辑中的任何名称一样,它意味着您将信号量初始化为“1”,它通常用于保护资源或受保护的变量以确保互斥。

【讨论】:

以上是关于Java 中的互斥量和信号量是啥?主要区别是啥?的主要内容,如果未能解决你的问题,请参考以下文章

互斥量和信号量 = 1 之间的区别? [复制]

互斥量和二进制信号量之间的实际区别

理解互斥量和信号量

java中的偏移量和偏移地址是啥

信号量与互斥锁区别

使用互斥量和信号量的屏障实现