在Scala中的变量上同步

在Scala中的变量上同步,scala,concurrency,Scala,Concurrency,问题是同时在几页文本中搜索感叹号,一旦任何线程找到它,所有其他线程都应该停止搜索 代码: 但后来我意识到,found不是一个固定的实例,因为它稍后会重新分配给一个新的选项对象。(为什么代码实际有效?) 所以我想出了一个解决办法: object AntiVolatile { case class Found(var isFound: Boolean) val pages = for (i <- 1 to 15) yield new Page("!Na" * rand.ne

问题是同时在几页文本中搜索感叹号,一旦任何线程找到它,所有其他线程都应该停止搜索

代码:

但后来我意识到,
found
不是一个固定的实例,因为它稍后会重新分配给一个新的
选项
对象。(为什么代码实际有效?)

所以我想出了一个解决办法:

  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)}")
      }
    }
  }
对象抗易失性{
已找到案例类(变量isFound:Boolean)
val pages=用于(i){
p、 位置=i
found.isFound=true
线程。睡眠(1)
}
案例=>
}
}
}否则i+=1
//如果仍然没有找到,请等待另一个线程找到它。
def wait():单位={
找到匹配项{
发现案例(错误)=>等待()
案例=>
}
}
等等
日志“结果:${pages.map({.position)}”)
}
}
}
这两个版本的行为似乎相同,为什么?我希望在第一个版本中会出现一些bug


链接到github repo:

不完全清楚您是否对学习并发感兴趣,或者您是否正在解决一个实际问题。尽管如此,我还是假设您正在尝试解决这个问题

为什么不使用期货

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)

}
import java.util.concurrent.TimeUnit
导入scala.concurrent.duration.duration
导入scala.concurrent.{ExecutionContext,wait,Future}
导入scala.util.Random
导入ExecutionContext.Implicits.global
对象主应用程序{
案例类页面(编号:Int,文本:String)
val pages=用于(i)未来{
val位置=p.text.indexOf(“!”)
s“在第${p.number}页的位置:$position处找到感叹号”
}}
val firstCompleted=Future.firstCompletedOf(searchFutures)
val结果=等待结果(首次完成,持续时间(5,时间单位秒))
println(结果)
}

似乎不起作用的“ok”对我来说,在任何一个版本中,结果集的大小都不应该完全相同,而且!始终位于第一个位置?也许我不了解
页面
的内部结构,我也不明白为什么您希望它们的行为完全不同。所有线程都为
foundInThread
创建一个值,并对其进行迭代(找不到
),直到他们完成各自的页面。同步只在最后进行(因此有点不相关),而且您似乎没有节省任何工作。此外,您正在所有线程上进行忙等待,这很糟糕:-(忙等待纯粹是为了演示目的。请参阅我添加的github链接)。
  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)}")
      }
    }
  }
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)

}