Scala で ReadWriteLock にローンパターンを使う
ReadWriteLock は確実にロックを解除しないといけません。
readWriteLock.writeLock().lock(); try { // 何かの処理 } finally { readWriteLock.writeLock().unlock(); }
いけませんが、よく忘れます。unlock()
がコピペの魔術かなにかで lock()
になったままとか。writeLock()
をロックして readLock()
をロック解除とか。
try-finally 句を使ってロックは確実にロック解除させるべきですが、ロックをかけるだけでコードが助長になります。
確実にリソースを閉じるときなど、ローンパターンを用いた using (with) 句がとても便利です。ということで、Scala で ReadWriteLock をするとき(あまり無いんじゃないかという話もありますが)、ローンパターンでロックを管理させるための、構文です。
object LoanPatternLock { import java.util.concurrent.locks.{Lock, ReadWriteLock} def lockWith[A <% Lock, B](l: A)(e: => B) = { l.lock() try e finally l.unlock() } def readLockWith[A <% ReadWriteLock, B](l: A)(e: => B) = lockWith(l.readLock)(e) def writeLockWith[A <% ReadWriteLock, B](l: A)(e: => B) = lockWith(l.writeLock)(e) }
使い方
import LoanPatternLock._ val lock = new java.util.concurrent.locks.ReentrantReadWriteLock val a = readLockWith(lock) { // どんな処理でもどんとこい }
オブジェクトで書いていますが、こういうパターンは自分の使っているエディタのコピペテンプレートに入れ、使いたいメソッドやクラスに貼付けることになります。
Glazed Lists を使っていて、ロックミスで油断しているとたまーにハマって悲しいのですが、ロックのバグはどこで起きたか、何が原因なのかが本当にわかりづらいです。個人用 PC でもマルチコアは普通な時代なので、デスクトップアプリケーション開発での平行処理はもはや必須です。なのできっとまたそのうち泣きを見ることになると思います。南無。