blog.bouzuya.net

2019-09-23 Kotlin の Singleton と Mutex

Kotlin の Singleton や Mutex のことを書く。正しいかは知らない。

ぼくはこの数ヶ月 Kotlin で Android アプリを書いている。そこで Singleton パターンを適用したいことがままある。だいたい↓みたいな形で書いている。

class K {
  companion object {
    @Volatile
    private var instance: K? = null

    fun getInstance(): K = instance ?: synchronized(this) {
      instance ?: K().also {
        instance = it
      }
    }
  }
}

現実には引数がないなら object で良いんじゃないかと思うけどコンパイルさえ通してない 30 秒で書いた例なので気にしないでほしい。 typo しているかもしれない。

あと↑みたいな double-checked locking はダメって Effective Java だかで読んだ記憶があるのだけど気にせず使っている。「この頃の JVM は賢いんだ」と自分に言い聞かせたり「 Android のそれが JVM なのかさえ知らないレベルの人間が雰囲気で書いているんだから仕方ないだろ」と逆ギレするなどしている。

さて。ここまでは前段。

↑のような synchronized(this) { ... } の中では suspend function は呼び出せない。「そりゃそうか」って感じではあるけどコンパイラに怒られるまでは考えたこともなかった。時間がないのでちょっと調べて出てきた Mutex で書いてみた。

https://kotlinlang.org/docs/reference/coroutines/shared-mutable-state-and-concurrency.html#mutual-exclusion

private val mutex = Mutex()
private var instance: K? = null

suspend fun getInstance(): K = instance ?: mutex.withLock {
  instance ?: init().also { // init は K を返す suspend function
    instance = it
  }
}

withLockmutex.lock(); try { ... } finally { mutex.unlock() } らしい。 mutex.lock() はおそらく lock を取れるなら進む取れないなら suspend 。 unlock はおそらく lock の解放。だからたぶん double-checked locking 的な動きになっているはず。正しいかは知らない。

「多分動くと思うからリリースしようぜ」って感じだ。