10.9 控制线程执行
我们已经见识到了,使用receive
时,每个actor是怎样运行在自己的线程里,react又如何让actor共享来自线程池的线程。不过,有时候我们会想要更强的控制力。比如,结束一个长期运行的任务之后,需要更新UI,这时需要在一个单独的线程里运行任务,然后,在主线程里更新UI。(因为UI组件时常不是线程安全的。)通过使用SingleThreadedScheduler
,可以让Scala在主线程里运行actor。我们用个例子看看如何做到这点:
ConcurrentProgramming/InMainThread.scala
import scala.actors._
import Actor._
if (args.length > 0 && args(0) == "Single"){
println("Command-line argument Single found")
Scheduler.impl = new SingleThreadedScheduler
}
println("Main running in " + Thread.currentThread)
actor { println("Actor1 running in " + Thread.currentThread) }
actor { println("Actor2 running in " + Thread.currentThread) }
receiveWithin(3000) { case _ => }
上面的代码里,创建了两个actor。如果不传任何命令行参数,两个actor的代码和主脚本的代码会运行在各自的线程里,输出如下:
Main running in Thread[main,5,main]
Actor2 running in Thread[Thread-5,5,main]
Actor1 running in Thread[Thread-3,5,main]
另一方面,如果像scala InMainThread.scala Single这样运行之前的代码,会得到不同的结果:
Command-line argument Single found
Main running in Thread[main,5,main]
Actor1 running in Thread[main,5,main]
Actor2 running in Thread[main,5,main]
无论actor何时启动,Scala都会让单例对象Scheduler
去运行它。通过设置Scheduler
的impl
,就可以控制整个应用的actor调度策略。
上面的方式影响深远;它让我们可以控制所有actor的调度。不过,也许我们想要让一些线程运行在主线程里,而其他actor运行在各自线程里。通过继承Actor
trait,改写scheduler()
方法,就可以做到这一点。默认情况下,这个方法为要调度的actor返回单例对象Scheduler
。改写这个方法就可以控制调度单独的actor的方式,如下所示:
ConcurrentProgramming/InMainThreadSelective.scala
import scala.actors._
import Actor._
trait SingleThreadedActor extends Actor {
override protected def scheduler() = new SingleThreadedScheduler
}
class MyActor1 extends Actor {
def act() = println("Actor1 running in " + Thread.currentThread)
}
class MyActor2 extends SingleThreadedActor {
def act() = println("Actor2 running in " + Thread.currentThread)
}
println("Main running in " + Thread.currentThread)
new MyActor1().start()
new MyActor2().start()
actor { println("Actor 3 running in " + Thread.currentThread) }
receiveWithin(5000) { case _ => }
上面的代码创建了三个actor,其中,两个继承自Actor
trait,一个使用了更为常规的actor()
方法。通过改写protected
方法scheduler()
,就可以控制MyActor2
的线程。运行上面的代码时,使用actor()
和MyActor1
创建的actor运行于自己的线程。而使用MyActor2
创建的actor则运行于主线程,如下所示:
Main running in Thread[main,5,main]
Actor1 running in Thread[Thread-2,5,main]
Actor2 running in Thread[main,5,main]
Actor 3 running in Thread[Thread-4,5,main]