【发布时间】:2016-01-17 13:17:06
【问题描述】:
问题是同时在几页文本中搜索感叹号,一旦任何线程找到它,所有其他线程都应该停止搜索。
代码:
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)
但后来我意识到found 不是一个常量实例,因为它稍后会重新分配给一个新的Option 对象。 (为什么代码实际上可以工作?)
所以我想出了一个解决办法:
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)}")
}
}
}
这两个版本的行为似乎相同,为什么?我希望在第一个版本中会出现一些错误。
【问题讨论】:
-
这在任何一个版本中对我来说似乎都不是“好的”,因为结果集的大小不应该都是一样的,而且 !总是在第一位?可能我没有得到
Page的内部结构 -
另外,我不明白你为什么期望他们表现不同。所有线程都为
foundInThread创建一个值并对其进行迭代(不是found),直到完成各自的页面。同步仅在最后(因此无关紧要),您似乎没有为自己节省任何工作。另外,你正在忙着等待所有线程,这很糟糕:-( -
忙碌的等待纯粹是为了演示。请看我添加的github链接。
标签: scala concurrency