Я пытаюсь выучить Scala и до сих пор считаю его отличным языком. Я учусь у "Начинающая Скала" Дэвида Поллака. В главе 3 есть этот фрагмент кода, который иллюстрирует, как писать многопоточный код без синхронизированных блоков (этот код скопирован из книги, он доступен для скачивания с сайта Apress , я не имею в виду нарушать какие-либо законы здесь):
import java.util.concurrent.atomic.{AtomicReference => AtomR, AtomicLong}
import java.util.Random
import scala.collection.immutable.TreeHashMap
object Multics {
type MT = Map[String, Int]
val info: AtomR[MT] = new AtomR(TreeHashMap.empty)
val clashCnt = new AtomicLong
def main(argv: Array[String]) {
runThread {
repeatEvery(1000) {
println("Clash Count: "+clashCnt+" Total: "+
info.get.foldLeft(0)(_ + _._2))
} }
for (i old + (name -> 0)}
repeatEvery(ran.nextInt(100)) {
doSet(info){old => old + (name -> (old(name) + 1))}
cnt = cnt + 1
if (cnt != info.get()(name))
throw new Exception("Thread: "+name+" failed")
} }
}
def runThread(f: => Unit) =
(new Thread(new Runnable {def run(): Unit = f})).start
def doSet[T](atom: AtomR[T])(update: T => T) {
val old = atom.get
if (atom.compareAndSet(old, update(old))) ()
else {
clashCnt.incrementAndGet
doSet(atom)(update)
}
}
def repeatEvery(len: => Int)(body: => Unit): Unit = {
try {
while(true) {
Thread.sleep(len)
body
}
} catch {
case e => e.printStackTrace; System.exit(1)
}
}
}
Насколько я понимаю, в функции doSet
есть потенциальная проблема с голоданием (неудачный поток всегда может конфликтовать и вызывать StackOverflowException). Прав ли я, и если да, то как можно улучшить этот код, чтобы решить эту проблему?