我正在尝试使用常规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()
有人可以帮我弄清楚我做错了什么吗?
不知道,我一生中没有使用过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(例如IO或Streams)来更好地建模这类事情。