【问题标题】:Using volatile variables and semaphores - Java使用 volatile 变量和信号量 - Java
【发布时间】:2015-07-20 10:05:41
【问题描述】:

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

有 2 个线程,一个增加,另一个减少变量,例如,显然,在每次访问之前,我有一个互斥锁,随时控制只有一个线程在“播放”变量。

需要定义为 volatile 吗?

【问题讨论】:

  • 为什么不使用AtomicLong 进行此类操作?在同一个整数上正确有效地实现并发操作并不容易。 JDK 中有现成的类可以为您完成这项工作。
  • 你为什么在这里使用信号量?

标签: java multithreading mutex semaphore volatile


【解决方案1】:

来自Semaphore的API文档:

内存一致性效果:线程中的操作在调用之前 “释放”方法,例如 release() happen-before 之后的操作 在另一个线程中成功“获取”方法,例如acquire()

所以读/写受信号量保护的变量是安全的。无需将它们声明为volatile

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • 当他不使用同步,只使用信号量时,你为什么认为互斥是通过同步实现的?
    • 因为在示例中,他说的是互斥锁,而从未提到同步,而且问题是关于信号量和易失性的。由于没有明确提及,我希望他的意思是同步的,因为信号量不适合这种情况
    【解决方案3】:

    我想知道当我使用信号量时是否有必要定义 可变为 volatile,

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

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

    实现没有实际的许可对象,而 Semaphore 有 不将分配的许可证与线程相关联,因此在 一个线程可以从另一个线程释放。你可以想到 获取与使用许可一样,释放与创建许可一样;一种 信号量不受创建它的许可数量的限制。

    对于您的场景,您可以共享一个计数器并使其不稳定或更好地使用AtomicInteger,因为他们使用CAS 机制,该机制在低争用情况下表现非常好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-14
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      • 1970-01-01
      相关资源
      最近更新 更多