Kotlinでsynchronizedを実現する

PHP出身の俺はスレッド周りの知識が非常に乏しい。
スレッドの勉強はときどきやってるんだけど、今回もその一環。
だが、Kotlinでやってる。
Javaの本を読みながら、synchronizedメソッドを実装しようとしたところ、なんとsynchronized修飾子がKotlinには存在しない!!
(synchonizedブロックはある)

synchronizedブロックで実現できるかなと思っていたのだが、自分のやり方が悪いのか、なんでかうまくいかなかったので、いろいろと調べていたら、Lockというのを発見した。

Lockを使うのが最近はよさそうらしい。ということで使ってみた。
ReentrantLockでLockを作り、withLockブロックで排他制御する。

このサンプルは、ボトルに入っている1000mlをyamadaとtanakaが200mlずつ飲んでいくというものである。
ちゃんと中身があることを確認した上で飲むというふうにしているのだが、中身があることを確認するタイミングがかぶると、あると思って飲み過ぎてマイナスになるので、withLockを使って排他制御している。
withLockが、飲む人がボトルを持っている状態と思ってもらえるとわかりやすい。

package com.okolabo.KotlinThreadChallenge

import kotlin.concurrent.thread
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock


fun main(args: Array<String>) {
    val bottle = Bottle()
    val drink = {
        while (bottle.drink(200)) {
            println(Thread.currentThread().getName() + " did drink water")
            Thread.sleep(200)
        }
    }

    val yamada = thread(name="yamada", block=drink)
    val tanaka = thread(name="tanaka", block=drink)
    yamada.join()
    tanaka.join()
    println("water: " + bottle.water)
}

class Bottle {
    var water = 1000
    class object {
        val lock = ReentrantLock()
    }

    private fun contains(amount : Int) : Boolean = amount <= water

    public fun drink(amount : Int) : Boolean {
        return lock.withLock {
            if (contains(amount)) {
                println("before water: " + water)
                water -= amount
                println("after water: " + water)
                true
            } else {
                false
            }
        }
    }
}

メソッド全体をlock.withLockで囲んでしまうことで、synchronizedメソッドっぽいことができるかなと思う。


タグ Kotlin | パーマリンク.

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です