Reentrantlock在Java中工作正常但在Scala中导致IllegalMonitorException

时间:2016-04-08 08:45:57

标签: java multithreading scala concurrency reentrantlock

我想迁移一个Java函数

protected static final Lock LOCK = new ReentrantLock();
public double calculate(...){
    try {
        LOCK.tryLock(20, TimeUnit.SECONDS);
        ...
    }finally{
        LOCK.unlock()
    }
}

Scala中的相同功能:

protected final def LOCK = new ReentrantLock
def calculate(...): double = {
    try{
        LOCK.tryLock(20, TimeUnit.Seconds)
        ...
    }finally{
        LOCK.unlock()
    }
}

LOCK.unlock()始终导致IllegalMonitorStateException。我没有看到为什么这是开心的原因。

有人可以告诉我问题在哪里吗?

1 个答案:

答案 0 :(得分:3)

您绝对应该LOCK成为val而不是def。 就目前而言,您每次都在重新创建ReetrantLock的新实例。你正在做的就是:

try {
    // Useless as we are creating a new lock
    (new ReentrantLock).tryLock(20, TimeUnit.SECONDS).tryLock(20, TimeUnit.SECONDS).tryLock(20, TimeUnit.SECONDS);
    ...
}finally{
    // Useless too, and will actually throw because we unlock a fresh (thus unlocked) lock
    (new ReentrantLock).unlock()
}

显然必然会失败。

您应该执行以下操作:

object MyClass {
  private val LOCK = new ReentrantLock
}
class MyClass {
  def calculate(...): double = {
      try{
          LOCK.tryLock(20, TimeUnit.Seconds)
          ...
      }finally{
          LOCK.unlock()
      }
  }
}

这是对原始java代码的scala的直接翻译。

最后,在他(现已删除)的回答中,Jon Skeet正确地建议:

  

如果你设法获得锁,你应该只解锁 - 而且   传统模式是在尝试之前调用lock / tryLock。   (与tryLock()无关,但它对lock()很重要,所以   我们也可以保持一致。)

给出了:

object MyClass {
  private val LOCK = new ReentrantLock
}
class MyClass {
  def calculate(...): double = {
      val gotLock = LOCK.tryLock(20, TimeUnit.Seconds)
      try {
          ...
      } finally {
        if (gotLock) {
          LOCK.unlock()
        }
      }
  }
}