在Scala中同步var [英] Synchronize on a var in Scala
问题描述
问题是在几个页面的文本之间搜索感叹号并发,一旦任何线程找到它,所有其他线程应该停止搜索。
The problem is to search among a few pages of text for an exclamation point concurrently and as soon as any of the threads finds it, all the other threads should stop searching.
代码:
object AntiVolatile {
val pages = for (i <- 1 to 15) yield new Page("!Na" * rand.nextInt(1000) + " Batman!", -1)
var found = Some(false)
def run(): Unit = {
for (p <- pages) yield thread {
var i = 0
var foundInThread = found.get
while (i < p.txt.length && !foundInThread)
if (p.txt(i) == '!') {
found.synchronized {
found match {
case Some(true) => foundInThread = true
case Some(false) => {
p.position = i
found = Some(true)
Thread.sleep(1)
}
case _ =>
}
}
} else i += 1
// if still not found, wait for another thread to find it.
def wait(): Unit = {
found match {
case Some(false) => wait()
case _ =>
}
}
wait()
log(s"results: ${pages.map(_.position)}")
}
}
}
似乎工作正常:
Thread-29: results: Vector(0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
Thread-27: results: Vector(0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
Thread-28: results: Vector(0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
Thread-26: results: Vector(0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
Thread-30: results: Vector(0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
Thread-31: results: Vector(0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
Thread-32: results: Vector(0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
Thread-25: results: Vector(0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
Thread-33: results: Vector(0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
Thread-34: results: Vector(0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
Thread-39: results: Vector(0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
Thread-38: results: Vector(0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
Thread-37: results: Vector(0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
Thread-36: results: Vector(0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
Thread-35: results: Vector(0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
但我意识到找到
一个常量实例,因为它会重新分配一个新的选项
对象。 (为什么代码实际工作?)
But then I realized that found
is not a constant instance because it's reassign to a new Option
object later. (Why does the code actually work?)
所以我想出了一个修复:
So I came up with a fix:
object AntiVolatile {
case class Found(var isFound: Boolean)
val pages = for (i <- 1 to 15) yield new Page("!Na" * rand.nextInt(1000) + " Batman!", -1)
val found = Found(false)
def run(): Unit = {
for (p <- pages) yield thread {
var i = 0
var foundInThread = found.isFound
while (i < p.txt.length && !foundInThread)
if (p.txt(i) == '!') {
found.synchronized {
found match {
case Found(true) => foundInThread = true
case Found(false) => {
p.position = i
found.isFound = true
Thread.sleep(1)
}
case _ =>
}
}
} else i += 1
// if still not found, wait for another thread to find it.
def wait(): Unit = {
found match {
case Found(false) => wait()
case _ =>
}
}
wait()
log(s"results: ${pages.map(_.position)}")
}
}
}
这两个版本看起来都是一样的,为什么?我希望在第一个版本中出现一些错误。
These two versions seem to behave the same, why? I would expect some bug cropping up in the first version.
链接到github repo: https://github.com/kindlychung/learnConcurrentScala/blob/master/src/main/scala/org/learningconcurrency/ch2/Ch2.scala p>
Link to github repo: https://github.com/kindlychung/learnConcurrentScala/blob/master/src/main/scala/org/learningconcurrency/ch2/Ch2.scala
推荐答案
如果你对学习并发感兴趣,或者如果你正在解决一个实际的问题,还不完全清楚。话说回来,我想假设你正试图解决这个问题。
It is not entirely clear if you are interested in learning concurrency or if you are solving an actual problem. With that being said, I am going to assume that you are attempting to solve the problem.
为什么不使用Futures?
Why not use Futures?
import java.util.concurrent.TimeUnit
import scala.concurrent.duration.Duration
import scala.concurrent.{ExecutionContext, Await, Future}
import scala.util.Random
import ExecutionContext.Implicits.global
object Main extends App {
case class Page(number: Int, text: String)
val pages = for (i <- 1 to 15) yield Page(i, "!Na" * Random.nextInt(1000) + " Batman! ")
val searchFutures = pages.map { p => Future {
val position = p.text.indexOf("!")
s"Exclamation mark found on page ${p.number} at position: $position"
}}
val firstCompleted = Future.firstCompletedOf(searchFutures)
val result = Await.result(firstCompleted, Duration(5, TimeUnit.SECONDS))
println(result)
}
这篇关于在Scala中同步var的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!