0

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 を引き起こしています。これが起こっている理由はわかりません。

誰かが問題がどこにあるか教えてもらえますか?

4

1 に答える 1

4

LOCKval代わりに必ず を作成する必要があり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()
        }
      }
  }
}
于 2016-04-08T09:01:47.740 に答える