Java编写互斥锁的最快方法?

互斥体在许多编程语言中很常见,例如C / C ++。 我在Java中想念他们。 但是,我可以通过多种方式编写自己的class Mutex

  • Mutex上使用简单的synchronized关键字。
  • 使用二进制信号量 。
  • 使用primefaces变量,如此处所讨论的。
  • …?

什么是最快(最好的运行时)方式? 我认为同步是最常见的,但性能呢?

互斥体在许多编程语言中很常见,例如C / C ++。 我在Java中想念他们。

不确定我是否跟着你(特别是因为你在问题中给出答案)。

 public class SomeClass { private final Object mutex = new Object(); public void someMethodThatNeedsAMutex() { synchronized(mutex) { //here you hold the mutex } } } 

或者,您可以简单地使整个方法同步,这相当于将this用作互斥对象:

 public class SomeClass { public synchronized void someMethodThatNeedsAMutex() { //here you hold the mutex } } 

什么是最快(最好的运行时)方式?

获取/发布监视器本身不会成为重要的性能问题(您可以阅读此博客文章以查看对影响的分析)。 但是如果你有许multithreading争夺锁定,它将产生争用并降低性能。

在这种情况下,最好的策略是如果你主要是读取数据而不使用“无锁”算法来使用互斥锁(正如Marko在评论中指出的那样,无锁使用CAS操作,这可能涉及多次重试写入如果你有很多写线程,最终导致更差的性能)甚至更好,避免在线程之间共享太多东西。

情况恰恰相反:Java设计师很好地解决了它,你甚至都不认识它:你不需要一流的Mutex对象,只需要synchronized修改器。

如果你有一个特殊的情况,你想以非嵌套的方式兼顾你的互斥体,那么ReentrantLockjava.util.concurrent总是提供丰富的同步工具,远远超出原始的互斥体。

在Java中,每个对象都可以用作Mutex。
这个对象通常被命名为“lock”或“mutex”。

您可以为自己创建该对象,这是首选变体,因为它避免了对该锁的外部访问:

  // usually a field in the class private Object mutex = new Object(); // later in methods synchronized(mutex) { // mutual exclusive section for all that uses synchronized // ob this mutex object } 

更快的是通过思考如果另一个线程读取非实际值会发生什么来避免互斥锁。 在某些情况下,这会产生错误的计算结果,而在其他结果中只产生最小的延迟。 (但比同步更快)

书中的详细解释

Java Concurreny在实践中

什么是最快(最好的运行时)方式?

这取决于很多事情。 例如, ReentrantLock用于在争用时比使用synchronized更好地执行,但是在发布新的HotSpot版本(优化synchronized锁定)时更改了。 因此,任何锁定方式都没有任何固有优势,有利于一种互斥体(从性能的角度来看) – 实际上,“最佳”解决方案可能会随着您正在处理的数据和您所使用的机器而改变继续前进。

另外,为什么Java的发明者没有为我解决这个问题?

他们做了 – 在几个方面: synchronizedLock s ,primefaces变量,以及java.util.concurrent一大堆其他实用程序。

您可以运行每个变体的微基准测试,例如primefaces,同步,锁定。 正如其他人所指出的那样,它在很大程度上取决于机器和使用中的线程数量。 在我自己的实验中递增长整数,我发现在Xeon W3520上只有一个线程,同步胜过primefaces:Atomic / Sync / Lock:8.4 / 6.2 / 21.8,每增量操作纳米。 这当然是一个边界案例,因为从来没有任何争论。 当然,在这种情况下,我们还可以查看非同步的单线程长增量,其速度比primefaces快6倍。
有4个线程,我得到21.8 / 40.2 / 57.3。 请注意,这些都是所有线程的增量,因此我们实际上看到了减速。 对于具有64个线程的锁,它会变得更好:22.2 / 45.1 / 45.9。
使用Xeon E7-4820的4路/ 64T机器上的另一个测试产生1个线程:9.1 / 7.8 / 29.1,4个线程:18.2 / 29.1 / 55.2和64个线程:53.7 / 402/420。
还有一个数据点,这次是双Xeon X5560,1T:6.6 / 5.8 / 17.8,4T:29.7 / 81.5 / 121,64T:31.2 / 73.4 / 71.6。
因此,在多插槽机器上,存在大量缓存一致性税。

您可以使用java.util.concurrent.locks.Lock,方法与mutex或java.util.concurrent.Semaphore相同。 但使用synchronized-keyword是一种更好的方法:-)

关心Andrej