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メソッドっぽいことができるかなと思う。