对于并发问题有两种处理方法,一种就是采用多线程方法;多个线程对共享的资源进行争夺,缺点在于破坏了操作的原子性以及潜在的死锁风险。
另一种思路就是消息机制,在要并发的对象中通过传递消息控制其操作,AkkaActor就是基于这一原理的工具。
下面试着用AkkaActor模拟上一篇文章中的转账过称。具体说明见注释。
package pers.machi.akkaconcurrent
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
object AkkaConcurrent {
def main(args: Array[String]): Unit = {
val Factory = ActorSystem("Factory")
//创建Actor对象工厂
var t1 = Factory.actorOf(Props[Transfer], "t1")
var t2 = Factory.actorOf(Props[Transfer], "t2")
//通过对象工厂取得Actor类的实例,类型为ActorRef
var from = Factory.actorOf(Props(new Account("from", 1000)), "from")
var to = Factory.actorOf(Props(new Account("to", 1500)), "to")
//还可以创建带参数的ActorRef
for (i <- 1 until 10) {
println(s"$i")
t1 ! TransferMessage(1, from, to, 200)
t2 ! TransferMessage(2, from, to, 400)
}
//重复十次取款存款
}
}
case class TransferMessage(id: Int, from: ActorRef, to: ActorRef, amt: Int)
case class WithDrawMessage(oid: Int, amt: Int, mto: ActorRef)
case class DepositeMessage(oid: Int, amt: Int)
//case clas,代表转账,扣款和存款三种操作,其成员包含ActorRef类
//转账类
class Transfer extends Actor {
override def receive: Receive = {
case TransferMessage(id, from, to, amt) => {
println(s"transfer $amt from $from to $to");
from ! WithDrawMessage(id, amt, to)
}
//如果收到转账消息,首先向to对象发送扣款消息
case "not_sufficient_money" =>
println("you totally broke")
//如果被扣款账号返回余额不足,显示 你是个穷鬼!
case _ => println("unknown message")
}
}
class Account(var name: String, var balance: Int) extends Actor {
override def receive: Receive = {
case WithDrawMessage(oid, amt, mto) => {
if (withdraw(amt)) {
mto ! DepositeMessage(oid, amt)
println(s"sending message to $mto")
} else
sender ! "not_sufficient_money"
}
//收到来自transfer的扣款消息,如果余额充足,扣款,发送给存款账户存款消息;否则向sender发送余额不足
case DepositeMessage(oid, amt) => {
deposit(amt)
println("you are rich")
}
//收到存款消息,存款,显示 有钱人
case _ => println("unknown message")
}
def deposit(amt: Int): Unit = {
balance += amt
System.out.println("RMB" + amt + " has been deposited into " + name)
}
//取款方法
def withdraw(amt: Int): Boolean = {
if (balance > amt) {
balance -= amt;
System.out.println("RMB" + amt + " has been withdrawed from " + name)
return true
} else {
System.out.println("not enough money, your loser")
return false
}
}
//存款方法
}
结果
1
2
3
4
5
6
7
8
9
transfer 200 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
transfer 400 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
transfer 400 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
transfer 200 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
RMB200 has been withdrawed from from
transfer 200 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
transfer 400 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
transfer 200 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
transfer 400 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
transfer 200 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
transfer 400 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
transfer 200 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
transfer 400 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
transfer 200 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
transfer 400 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
transfer 200 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
transfer 400 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
transfer 200 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
RMB200 has been deposited into to
you are rich
sending message to Actor[akka://Factory/user/to#-155185484]
RMB400 has been withdrawed from from
transfer 400 from Actor[akka://Factory/user/from#-98407958] to Actor[akka://Factory/user/to#-155185484]
RMB400 has been deposited into to
you are rich
sending message to Actor[akka://Factory/user/to#-155185484]
not enough money, your loser
RMB200 has been withdrawed from from
you totally broke
RMB200 has been deposited into to
you are rich
sending message to Actor[akka://Factory/user/to#-155185484]
not enough money, your loser
not enough money, your loser
you totally broke
you totally broke
not enough money, your loser
not enough money, your loser
you totally broke
you totally broke
not enough money, your loser
not enough money, your loser
you totally broke
not enough money, your loser
not enough money, your loser
you totally broke
you totally broke
not enough money, your loser
not enough money, your loser
you totally broke
you totally broke
you totally broke
not enough money, your loser
you totally broke
not enough money, your loser
not enough money, your loser
not enough money, your loser
you totally broke
you totally broke
you totally broke