在scala中也可以像java中那样使用多线程,scala中如果像java中那样实现多线程的话需要实现;Runnable或者Callable
runable没有返回值
trait Runnable {
def run(): Unit
}
Callable有一个返回值
trait Callable[V] {
def call(): V
}
scala并发是建立在java基础上的
val hello =
new
Thread(
new
Runnable {
def run() {
println(
"hello world"
)
}
})hello.start
这是scala简单实现java中的多线程,但是由于Java中的多线程是通过共享数据和线程锁来实现的,这样就有可能就会有死锁的情况。
scala中actor模式通过消息的方式来实现并发,由于通过消息来实现,所以就不会有java中的死锁情况出现
scala中常用的就是乒乓的例子
ping pong actor
package testScala
import akka.actor._
case object PingMessage
case object PongMessage
case object StartMessage
case object StopMessage
class Ping(pong:ActorRef) extends Actor{
var count= 0
def incrementAndPrint{count+=1;println("ping")}
override def receive: Receive = {
case StartMessage =>
incrementAndPrint
pong ! PingMessage
case PongMessage =>
incrementAndPrint
if(count>99){
sender ! StopMessage
println("ping stopped")
context.stop(self)
}else{
sender ! PingMessage
}
case _ =>println("Ping got something unexpected")
}
}
class Pong extends Actor{
override def receive: Receive = {
case PingMessage =>
println("pong")
sender ! PongMessage
case StopMessage =>
println("pong stopped")
context.stop(self)
case _ =>println("pong got something unexpected")
}
}
object PingPongTest{
def main(args: Array[String]): Unit = {
val system = ActorSystem("pingpongsytem")
val pong = system.actorOf(Props[Pong],name="pong")
val ping = system.actorOf(Props(new Ping(pong)),name="ping")
ping ! StartMessage
//system.shutdown
}
}
1.创建一个ActorSystem
2.创建pong,一个Pong actor的实例(Pong对象实际上是一个ActorRef)
3.创建ping,ping actor一个实例Ping actor构造函数需要一个ActorRef
3.创建ping,ping actor一个实例Ping actor构造函数需要一个ActorRef
4.发送StartMessage开始
一旦ping收到StartMessage,actor以尽可能快的速度彼此来回发消息,直到ping中的计数达到上限,消息通过 !方法发送
一开始,Ping类需要一个Pong actor的初始引用,一旦行动开始,两个actor智慧使用收到的隐式的发送者的引用来彼此互发
乒乓消息,直到Ping actor达到接收限制,到那个时候看,他会发一个停止消息给Pong actor,然后两个actor都会调用他们
的context.stop方法。
acotr构造函数:调用事件和其他类一样在类的实例创建
preStart:actor启用时立即调用,重启事被postRestart调用
postStop:actor停止后调用,可以用来执行清理工作
preRestart:actor重启时,进程通知旧的actor,引起重启的异常调用preRestart方法,而消息触发异常,、
postRestart:引起重启的异常触发了新的actor的postRestart方法,缺省会调用preStart方法
以上四行话是直接引用的官方,但是我自己的理解如果以启动actor就会调用preStart方法,构造函数里面直接打印 不一定在preStart前面,因为actor是异步启动的。如果系统抛出一个异常,actor系统会首先1.调用preRestart 2.调用postStop 3.打印出异常信息 4.调用构造函数 5调用postRestart 6.调用preStart。其实4应该在5后面,因为按照官方文档说的 postRestart会触发一个新的actor,触发一个新的actor后才会有构造函数和preStart,并且调用了新的actor的postRestart,但是由于新的actor缺省所以会调用preStart方法 。postStop是人为主动调用的例如:system.stop(kenny) 此时会调用postStop。如果调用shutdown就直接shutdown了
package testScala
import akka.actor.Actor.Receive
import akka.actor._
/**
* Author: Dlin
* Date:2017/7/28 15:25
* Descripe:
*/
case object ForceRestart
class Kenny extends Actor{
println("entered the kenny constructor")
override def preStart(): Unit = {
println("Kenny :preStart")
}
override def postStop(): Unit = {
println("kenny :postStop")
}
override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
println("kenny:preRestart")
println(s" preRestart message: ${message.getOrElse("")}")
println(s" preRestart resason: ${reason.getMessage}")
super.preRestart(reason,message)
}
override def postRestart(reason: Throwable): Unit = {
println("kenny :postRestart")
println(s" postResart reason:${reason.getMessage}")
super.postRestart(reason)
}
override def receive: Receive = {
case ForceRestart => throw new Exception("boom")
case _ => println("kenny receive a message")
}
}
object DeathWatchTest {
def main(args:Array[String]):Unit= {
val system = ActorSystem("kenny")
val kenny = system.actorOf(Props[Kenny], name = "kennytest")
println("sending kenny a simple string message")
kenny ! "hello"
Thread.sleep(5000)
println("--------------------------------------------")
println("make kenny restart")
kenny ! ForceRestart
Thread.sleep(5000)
println("--------------------------------------------")
println("stopping kenny")
system.stop(kenny)
Thread.sleep(5000)
println("--------------------------------------------")
println("shutting down system")
system.shutdown()
println("--------------------------------------------")
}
}