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

时间:2013-01-15 12:03:28

标签: java multithreading performance mutex

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

  • Mutex上使用简单的synchronized关键字。
  • 使用二进制semaphore
  • 使用原子变量,如讨论here
  • ...?

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

6 个答案:

答案 0 :(得分:14)

  

互斥体在许多编程语言中很常见,例如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
    }
}
  

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

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

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

答案 1 :(得分:5)

情况正好相反:Java设计师解决了它那么好你甚至都不认识它:你不需要一流的Mutex对象,只需{ {1}}修饰符。

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

答案 2 :(得分:3)

在Java中,每个对象都可以用作互斥锁 这个对象通常被命名为“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

答案 3 :(得分:2)

  

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

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

  

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

他们以多种方式做到了:synchronizedLocks,原子变量以及java.util.concurrent中的大量其他实用程序。

答案 4 :(得分:1)

您可以运行每个变体的微基准测试,例如原子,同步,锁定。正如其他人所指出的,它在很大程度上取决于机器和使用中的线程数量。在我自己的实验中递增长整数,我发现在Xeon W3520上只有一个线程,同步胜过原子:Atomic / Sync / Lock:8.4 / 6.2 / 21.8,每增量操作纳米。 这当然是一个边界案例,因为从来没有任何争论。当然,在这种情况下,我们还可以查看非同步的单线程长增量,其速度比原子快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。 因此,在多插槽机器上,存在大量缓存一致性税。

答案 5 :(得分:-1)

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

此致 安德烈