java 与信号量同步还是与监视器同步更好?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5083818/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 09:19:31  来源:igfitidea点击:

Is it better to synchronize with semaphores or with monitors?

javasynchronizationmonitor

提问by farm ostrich

Is it better to synchronize with semaphores or with monitors?

与信号量同步还是与监视器同步更好?

回答by JYelton

"Better" depends on context. They are "equally powerful" according to James McParlane. I highly recommend viewing his blog for a discussion on the differences.

“更好”取决于上下文。根据詹姆斯·麦克帕兰 (James McParlane) 的说法,它们“同样强大”。我强烈建议查看他的博客以讨论差异

Here is a quick guide I found:

这是我找到的快速指南:

Semaphores

信号量

  • Can be used anywhere in a program, but should not be used in a monitor
  • Wait()does not always block the caller (i.e., when the semaphore counter is greater than zero).
  • Signal()either releases a blocked thread, if there is one, or increases the semaphore counter.
  • If Signal()releases a blocked thread, the caller and the released thread both continue.
  • 可以在程序中的任何地方使用,但不应在监视器中使用
  • Wait()并不总是阻塞调用者(即,当信号量计数器大于零时)。
  • Signal()要么释放一个被阻塞的线程(如果有),要么增加信号量计数器。
  • 如果Signal()释放阻塞的线程,调用者和释放的线程都会继续。

Condition Variables

条件变量

  • Can only be used in monitors
  • Wait()always blocks the caller.
  • Signal()either releases a blocked thread, if there is one, or the signal is lost as if it never happens.
  • If Signal()releases a blocked thread, the caller yields the monitor (Hoare type) or continues (Mesa Type). Only one of the caller or the released thread can continue, but not both.
  • 只能在显示器中使用
  • Wait()总是阻止调用者。
  • Signal()要么释放一个被阻塞的线程(如果有),要么信号丢失,就好像它从未发生过一样。
  • 如果Signal()释放一个阻塞的线程,调用者让出监视器(Hoare 类型)或继续(Mesa 类型)。只有调用者或释放的线程之一可以继续,但不能同时继续。

This information from: http://www.cs.mtu.edu/~shene/NSF-3/e-Book/MONITOR/sema-vs-monitor.html

此信息来自:http: //www.cs.mtu.edu/~shene/NSF-3/e-Book/MONITOR/sema-vs-monitor.html

Some useful resources:

一些有用的资源:

回答by Jirka Hanika

If you are after headache minimization, prefer the monitors(synchronizedblocks/methods) over semaphores wherever you feel a real choice of a locking primitive. Ignore academical talk about flexibility of semaphores. You are after reliability, not configurability, aren't you?

如果您追求头痛最小化,那么synchronized在您觉得真正选择锁定原语的任何地方,都更喜欢监视器(块/方法)而不是信号量。忽略关于信号量灵活性的学术讨论。您追求的是可靠性,而不是可配置性,不是吗?

It is often claimed that monitors and semaphores are equivalent (can simulate each other), but this equivalence is far more abstract and less helpful than is sometimes expected. Anyone who can correctlysimulate one with the other does not need any answer to this question anymore.

人们经常声称监视器和信号量是等价的(可以相互模拟),但这种等价比有时预期的要抽象得多,用处更小。任何能够正确模拟一个与另一个的人不再需要对这个问题的任何答案。

Obviously, semaphores are your only practical choice in situations where the number of threads to be allowed to simultaneously enter a block is larger than one. So the real competitor of monitors are binary semaphores, namely those that are initialized with a count of 1, and additionally only those of them where you expect the same thread that did the locking to eventually unlock the semaphore. So let's look closer at exactly those situations.

显然,在允许同时进入一个块的线程数大于 1 的情况下,信号量是唯一实用的选择。所以监视器的真正竞争对手是二进制信号量,即那些初始化为 1 的信号量,另外只有那些你期望执行锁定的线程最终解锁信号量的那些。因此,让我们仔细看看这些情况。

The fundamental difference between monitors and binary semaphores is thread ownership. It has a big consequence, and that is the capability of reentrancy. Reentrancy means that a thread that already owns a lock can acquire it again as opposed to deadlocking. This is a big deal if your class has shared state that you simply want to protect in all methods but cannot afford permanent assumptions about how these methods call each other; or with any belt and braces traits that evolve in your thread safety scheme in general.

监视器和二进制信号量之间的根本区别是线程所有权。它有一个很大的后果,那就是可重入能力。重入意味着已经拥有锁的线程可以再次获取它,而不是死锁。如果您的类具有共享状态,而您只是想在所有方法中保护这些状态,但无法承受关于这些方法如何相互调用的永久假设,那么这将是一个大问题;或者在您的线程安全方案中总体上演变的任何腰带和支架特征。

Semaphores are never reentrant and Java monitors are always reentrant.If you need to lock the same object from many code locations, semaphores are prone to deadlockseven in single threaded scenarios - and this limitation of semaphores brings any benefits only in relatively rare scenarios where monitors are not really an option anyway.

信号量永远不会重入,而 Java 监视器总是可重入的。如果您需要从多个代码位置锁定同一个对象,即使在单线程场景中,信号量也容易出现死锁——而信号量的这种限制只在相对罕见的场景中带来任何好处,因为无论如何监视器都不是真正的选择。

Thread ownership also drammatically reduces the risk of forgetting to lock, forgetting to unlock, or one thread's activities masking activities of another thread. There is also a significant ergonomic difference in the associated Java syntax.

线程所有权还显着降低了忘记锁定、忘记解锁或一个线程的活动掩盖另一个线程的活动的风险。在相关的 Java 语法中也存在显着的人体工程学差异。

Notice also this question; although it uses a different terminology, the better answers there understand "mutex" to mean a Java "monitor".

还要注意这个问题;尽管它使用不同的术语,但更好的答案是将“互斥锁”理解为 Java“监视器”。

回答by Air

To confirm, by monitorswe mean the good old synchronizedkeyword.

确认一下,监视器是指good oldsynchronized关键字。

First question, do you need your lock to have a counter?

第一个问题,你需要你的锁有一个计数器吗?

  1. A Semaphore can have a counter greater than one. If you need to protect N resources, the Semaphore is best. Easy decision.
  2. If you're protecting a single resource, this is the interesting case where a Semaphore(1) and monitor are equally applicable.
  1. 信号量可以有一个大于 1计数器。如果需要保护N个资源,最好使用Semaphore。轻松决定。
  2. 如果您要保护单个资源,这是一个有趣的案例,其中 Semaphore(1) 和监视器同样适用。

The J2SE 5.0 concurrency articlegives great advice here. Monitors are limited because :

J2SE 5.0并发文章在这里给出了很好的建议。监视器有限,因为:

  • No way to back offfrom an attempt to acquire a lock that is already held, or to give up after waiting for a specified period of time, or to cancel a lock attempt after an interrupt.
  • No way to alter the semanticsof a lock, for example, with respect to reentrancy, read versus write protection, or fairness.
  • Synchronization is done within methods and blocks, thus limiting use to strict block-structured locking. In other words, you cannot acquire a lock in one method and release it in another.
  • 无法从获取已持有的锁的尝试中退出,或在等待指定的时间段后放弃,或在中断后取消锁定尝试。
  • 无法改变的语义,例如,关于可重入性、读写保护或公平性。
  • 同步是在方法和块内完成的,因此将使用限制为严格的块结构锁定。换句话说,您不能在一种方法中获得锁并在另一种方法中释放它

So if any of these items is important to you - backing off after a timeout is a great example - then go with a Semaphore. If not, a monitor is fine.

因此,如果这些项目中的任何一项对您很重要 - 在超时后退出是一个很好的例子 - 那么请使用信号量。如果没有,显示器很好。

回答by JeanValjean

First of all, you have to decide which JDK are you using. The first Java releases where only provided of Threads. Since the Java Tiger (5.0), new classes have been introduced to handle concurrency. In particular, a complete package has been provided, the java.util.concurrent.

首先,您必须确定您使用的是哪个 JDK。第一个 Java 版本只提供了线程。从 Java Tiger (5.0) 开始,引入了新的类来处理并发。特别是,提供了一个完整的包java.util.concurrent

In my experience, I found that monitors are better, since they let the code more clean. Moreover, using them let the code more easy-to-understand. They are generally implemented through a class that implements the Lockinterface: the most famous implementations provided by the JDK are the ReentrantLockclass, which defines a general lock, and the ReentrantReadWriteLockclass, that provides a specific writeand/or readlock.

根据我的经验,我发现监视器更好,因为它们让代码更干净。此外,使用它们让代码更易于理解。它们通常通过一个实现Lock接口的类来实现:JDK 提供的最著名的实现是ReentrantLock类,它定义了一个通用锁,以及ReentrantReadWriteLock类,它提供了一个特定的和/或锁。

Threfore, a lock is used to enable/disable the access to a shared object (e.g. a list of objects).

因此,锁用于启用/禁用对共享对象(例如对象列表)的访问。

A Semaphoreobject is a synchronized used to coordinate and control the threads (there are many synchronizers provided in the latest JDKs, like Semaphore, CyclicBarrier, CountdownLatch, and Exchangerclasses). For instance, with a Semaphore you can release a fixed number of tokens to your pool of Threads and so decide the amount of operations that can be executed simultaneously. Personally, I don't like this approach, since the use of a pool of thread with Futures and Locks lead to the same result in a cleaner and safer way.

信号量对象是同步的用于协调和控制线(有在最新的JDK提供,像许多同步信号量的CyclicBarrierCountdownLatch类)。例如,使用信号量,您可以向线程池释放固定数量的令牌,从而决定可以同时执行的操作数量。就我个人而言,我不喜欢这种方法,因为使用带有 Futures 和 Locks 的线程池会以更干净、更安全的方式产生相同的结果。

More info can be found in this book: "Java Concurrency in Practice" and in this IBM's tutorial: "Concurrency in JDK 5.0". Some more nice examples can be found here.

更多信息可以在这本书中找到:“ Java 并发实践”和 IBM 的教程:“ JDK 5.0 中的并发”。可以在此处找到一些更好的示例。