RosettaCodeData/Task/Atomic-updates/Kotlin/atomic-updates.kotlin
2018-06-22 20:57:24 +00:00

84 lines
2.6 KiB
Text

// version 1.2.0
import java.util.concurrent.ThreadLocalRandom
import kotlin.concurrent.thread
const val NUM_BUCKETS = 10
class Buckets(data: IntArray) {
private val data = data.copyOf()
operator fun get(index: Int) = synchronized(data) { data[index] }
fun transfer(srcIndex: Int, dstIndex: Int, amount: Int): Int {
if (amount < 0) {
throw IllegalArgumentException("Negative amount: $amount")
}
if (amount == 0) return 0
synchronized(data) {
var a = amount
if (data[srcIndex] - a < 0) a = data[srcIndex]
if (data[dstIndex] + a < 0) a = Int.MAX_VALUE - data[dstIndex]
if (a < 0) throw IllegalStateException()
data[srcIndex] -= a
data[dstIndex] += a
return a
}
}
val buckets get() = synchronized(data) { data.copyOf() }
fun transferRandomAmount() {
val rnd = ThreadLocalRandom.current()
while (true) {
val srcIndex = rnd.nextInt(NUM_BUCKETS)
val dstIndex = rnd.nextInt(NUM_BUCKETS)
val amount = rnd.nextInt() and Int.MAX_VALUE
transfer(srcIndex, dstIndex, amount)
}
}
fun equalize() {
val rnd = ThreadLocalRandom.current()
while (true) {
val srcIndex = rnd.nextInt(NUM_BUCKETS)
val dstIndex = rnd.nextInt(NUM_BUCKETS)
val amount = (this[srcIndex] - this[dstIndex]) / 2
if (amount >= 0) transfer(srcIndex, dstIndex, amount)
}
}
fun print() {
while (true) {
val nextPrintTime = System.currentTimeMillis() + 3000
while (true) {
val now = System.currentTimeMillis()
if (now >= nextPrintTime) break
try {
Thread.sleep(nextPrintTime - now)
}
catch (e: InterruptedException) {
return
}
}
val bucketValues = buckets
println("Current values: ${bucketValues.total} ${bucketValues.asList()}")
}
}
}
val IntArray.total: Long get() {
var sum = 0L
for (d in this) sum += d
return sum
}
fun main(args: Array<String>) {
val rnd = ThreadLocalRandom.current()
val values = IntArray(NUM_BUCKETS) { rnd.nextInt() and Int.MAX_VALUE }
println("Initial array: ${values.total} ${values.asList()}")
val buckets = Buckets(values)
thread(name = "equalizer") { buckets.equalize() }
thread(name = "transferrer") { buckets.transferRandomAmount() }
thread(name = "printer") { buckets.print() }
}