使用可变变量和信号量 - Java

Using volatile variables and semaphores - Java

我从线程、信号量、易失性变量等开始。 我想知道当我使用 Semaphores 时是否有必要将变量定义为 volatile,我的意思是:

有 2 个线程,一个增加变量,另一个减少变量,显然,在每次访问之前,我有一个互斥体,它随时控制只有一个线程 "playing" 与变量。

是否需要定义为volatile?

I wonder if when I'm using Semaphores it is necessary to define the variable as volatile,

我认为没有这样的限制。互斥量是一种互斥信号量,是信号量的一种特殊变体,一次只允许一个储物柜。它相当于一个计数为1的普通计数信号量,并且要求它只能由锁定它的同一个线程释放。

如果我们在 Java 中专门讨论 信号量:信号量是许可的计数器,获取就像递减,等待而不是低于零。它没有上限。如 CIP 中所述:

The implementation has no actual permit objects, and Semaphore does not associate dispensed permits with threads, so a permit acquired in one thread can be released from another thread. You can think of acquire as consuming a permit and release as creating one; a Semaphore is not limited to the number of permits it was created with.

对于您的方案,您可以共享一个计数器并使其易变或更好地使用 AtomicInteger,因为它们使用 CAS 机制,在低竞争下表现非常好。

来自 Semaphore 的 API 文档:

Memory consistency effects: Actions in a thread prior to calling a "release" method such as release() happen-before actions following a successful "acquire" method such as acquire() in another thread.

因此 read/write 由信号量保护的变量是安全的。无需将它们声明为 volatile.

信号量不应该用来代替synchronized,因为信号量不持有独占互锁,即使它被初始化为一个,就像一些对象上的synchronized。的确,信号量初始化为一个,一次只允许一个线程访问持有许可的对象。但是持有许可的线程并不拥有它,任何其他线程都可以释放该许可并获得许可。因此,两个线程可以同时访问同一个对象,如果两个线程都操作该对象,则会出现多线程问题,如丢失更新、过时读取等。

在你有 2 个线程的例子中,一个增加一个减少同一个变量。互斥就足够了,不需要 volatile 声明。这里我假设互斥是通过同步而不是信号量实现的。

volatile 不如 synchronized 严格,当执行的操作是原子的(读取或写入) 时,您可能希望使用 volatile。执行 read-update-write 操作时不应使用 volatile。