Warm tip: This article is reproduced from serverfault.com, please click

concurrency-Scala交替打印foo / bar

(concurrency - Scala print foo/bar alternately)

发布于 2020-12-01 22:20:24

我正在尝试使用常规Runnables和wait(),notifyAll()在Scala中交替编码此foo / bar的LeetCode练习代码,以打印foo / bar,但无法获取它来生成所需的输出,该输出应该是:

foo bar foo bar foo bar foo bar foo bar 

这是代码:

import scala.concurrent.ExecutionContext.Implicits.global

class Foo extends Runnable {
  @Override def run(): Unit = { print("foo ") }
}

class Bar extends Runnable {
  @Override def run(): Unit = { print("bar ") }
}

val printFoo = new Foo
val printBar = new Bar

class FooBar {
  private var foosLoop: Boolean = false

  @throws(classOf[InterruptedException])
  def foo: Unit = for (_ <- 1 to 5) synchronized {
      while (foosLoop) { wait() }
      printFoo.run()
      foosLoop = true
      notifyAll()
    }

  @throws(classOf[InterruptedException])
  def bar: Unit = for (_ <- 1 to 5) synchronized {
      while (!foosLoop) { wait() }
      printBar.run()
      foosLoop = false
      notifyAll()
    }
}

val fb = new FooBar
fb.foo
fb.bar

// Output:
// foo    <=== prints only first "foo "

有人可以帮我弄清楚我做错了什么吗?

我的第二个问题是:可以用Scala Futures代替Runnables来实现吗?

更新

实际上,发布的代码可以正常工作,fb.foo并且fb.bar可以从单独的线程中调用它们。

val tFoo = new Thread (new Runnable { @Override def run(): Unit = fb.foo })
val tBar = new Thread (new Runnable { @Override def run(): Unit = fb.bar })

tFoo.start()
tBar.start()
Questioner
Test Mirror
Viewed
0
Luis Miguel Mejía Suárez 2020-12-02 06:41:42

有人可以帮我弄清楚我做错了什么吗?

不知道,我一生中没有使用过Runnables,而且Scala中也没有使用过它们
(我会说Java也不再使用它了

可以用Scala Futures代替Runnables来实现吗?

是的,是这样的:

import java.util.concurrent.Semaphore
import scala.concurrent.{ExecutionContext, Future}

object RunAlternately {
  /**
   * Runs two taks concurrently and alternating between the two.
   * @param n the amout of times to run each task.
   * @param aTaks the first task.
   * @param bTaks the second task.
   */
  def apply(n: Int)(aTask: => Unit)(bTask: => Unit)(implicit ec: ExecutionContext): Future[Unit] ={
    val aLock = new Semaphore(1)
    val bLock = new Semaphore(0)
    
    def runOne(task: => Unit, thisLock: Semaphore, thatLock: Semaphore): Future[Unit] =
      Future {
        var i = 0
        while (i < n) {
          thisLock.acquire()
          task
          thatLock.release()
          i += 1
        }
      }
    
    val aFuture = runOne(aTask, thisLock = aLock, thatLock = bLock)
    val bFuture = runOne(bTask, thisLock = bLock, thatLock = aLock)
    
    aFuture.flatMap(_ => bFuture)
  }
}

看到它在这里运行


但是,通常使用更高级别的IO(例如IOStreams)来更好地建模这类事情