最近在看一些游戏群里面都在讨论actor,以前还真没接触过,赶紧了解一下。
感觉最经典的总结就是那句:万物皆Actor。Actor之间只有发送消息这一种通信方式,消息让Actor之间解耦;Actor模型的消息传递形式简化了并行程序的开发。自己做的2个游戏项目都用了不同的并发处理模型,在此做一个总结。
1.actor模式
java平台目前还不支持actor,但并不影响我们使用actor,目前已经有多种支持actor的库,如akka,μJavaActors 库,这是一个轻型的、基于 Java 的 actor 包,用于在传统 Java 应用程序中实现高度并行的执行。
这里打算用μJavaActors 库做一个简单的实例。
具体μJavaActors 库参考:http://www.ibm.com/developerworks/cn/java/j-javaactors/#resources
public class GamePlayerActor extends AbstractActor {
private int gold;// 玩家金币
@Override
protected void loopBody(Message arg0) {
String subject = arg0.getSubject();
if (!subject.equals("init")) {
int count = (Integer) arg0.getData();
setGold(getGold() + count);
System.out.println(subject + ",金币+" + count + ",总金币=" + getGold());
}
}
//省略get/set...
}
玩家actor,接受各种类型的金币获取
public class ResourceActor extends AbstractActor {
private Actor sendTo;
@Override
protected void runBody() {
DefaultMessage m = new DefaultMessage("资源收获", 50);
getManager().send(m, this, sendTo);
}
@Override
protected void loopBody(Message arg0) {
}
public void setSendTo(Actor sendTo) {
this.sendTo = sendTo;
}
}
资源actor,获取金币的途径,相信玩过一下策略类游戏的都知道有收获资源。
public class RewardActor extends AbstractActor {
private Actor sendTo;
@Override
protected void runBody() {
DefaultMessage m = new DefaultMessage("奖励", 100);
getManager().send(m, this, sendTo);
}
@Override
protected void loopBody(Message arg0) {
}
public void setSendTo(Actor sendTo) {
this.sendTo = sendTo;
}
}
奖励actor, 获取金币的途径,发送奖励获得金币。
下面是一个测试类:
public class Main {
public static void main(String[] args) {
final DefaultActorManager am = new DefaultActorManager();
try {
Map<String, Object> options = new HashMap<String, Object>();
options.put(DefaultActorManager.ACTOR_THREAD_COUNT, 20);
am.initialize(options);
final GamePlayerActor gamePlayerActor = (GamePlayerActor) am
.createActor(GamePlayerActor.class, "gamePlayerActor");
// 接受消息actor
am.startActor(gamePlayerActor);
for (int i = 0; i < 10; i++) {
final int k = i;
new Thread(new Runnable() {
@Override
public void run() {
ResourceActor a = (ResourceActor) am.createActor(
ResourceActor.class, "a" + k);
RewardActor b = (RewardActor) am.createActor(
RewardActor.class, "b" + k);
a.setSendTo(gamePlayerActor);
b.setSendTo(gamePlayerActor);
// 发送消息actor
am.startActor(a);
am.startActor(b);
}
}).start();
}
Thread.sleep(100000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果:(预期结果是1500,实际结果也是1500)
资源收获,金币+50,总金币=50
资源收获,金币+50,总金币=100
资源收获,金币+50,总金币=150
奖励,金币+100,总金币=250
奖励,金币+100,总金币=350
资源收获,金币+50,总金币=400
资源收获,金币+50,总金币=450
奖励,金币+100,总金币=550
奖励,金币+100,总金币=650
资源收获,金币+50,总金币=700
资源收获,金币+50,总金币=750
奖励,金币+100,总金币=850
奖励,金币+100,总金币=950
奖励,金币+100,总金币=1050
奖励,金币+100,总金币=1150
资源收获,金币+50,总金币=1200
资源收获,金币+50,总金币=1250
资源收获,金币+50,总金币=1300
奖励,金币+100,总金币=1400
奖励,金币+100,总金币=1500
2.大家最熟悉的java并发处理
synchronized 代码块、wait/notify 和 java.util.concurrent 包等关键字,刚开始做第一个游戏的时候,就使用的这种方式。整个游戏只有一个vm,我们通过封装了一下ehcache,将玩家的信息都保存在本地内存中,玩家的每一块信息在内存中都只存在一份,比如gameplayer,在内存中只存在一个对象 gameplayer,整个代码中都是这种模式:
public class GamePlayer {
private int glod;
public synchronized void addGold(int count) {
this.glod += count;
}
//略...
}
3.队列模式
这种模式也是当前游戏中正在使用的,给每个玩家一个消息队列,对某一个玩家来讲,其实都是一个单线程。
private OrderedQueuePoolExecutor recvExcutor = new OrderedQueuePoolExecutor(
"消息接收队列", 100, 10000);
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
Message request = (Message) e.getMessage();
recvExcutor.addTask(request.getHeader().getSessionid(), new MWork(
request, e.getChannel()));
}
OrderedQueuePoolExecutor 是一个有序的队列线程池(这里代码就不贴了),这里其实就是用每个玩家的session关联一个消息队列,其实有点想actor模式。
总结:actor应该是一种很好的模式,而且也提供了一些成熟的框架,但是使用Actor模型编写应用程序,需要开发人员使用一种与以往不同的设计思路,这样的思路说难倒不难,说简单也不简单。第三种队列模式我觉得更加简单。