package com.github.shansun.sparrow.actor.internal; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import com.github.shansun.sparrow.actor.api.MessageQueue; import com.github.shansun.sparrow.actor.api.MessageRedcapCallback; import com.github.shansun.sparrow.actor.constant.Constants; import com.github.shansun.sparrow.actor.spi.AbstractActor; import com.github.shansun.sparrow.actor.spi.ActorManager; import com.github.shansun.sparrow.actor.statistic.Statistics; import com.github.shansun.sparrow.actor.util.RejectedMessageHandlers; import org.slf4j.Logger; import com.google.common.base.Preconditions; import com.google.common.base.Throwables; import com.google.common.collect.HashMultiset; import com.google.common.collect.Lists; import com.google.common.collect.Multiset; import com.github.shansun.sparrow.actor.api.Actor; import com.github.shansun.sparrow.actor.api.Message; import com.github.shansun.sparrow.actor.api.RejectedMessageHandler; import com.github.shansun.sparrow.actor.statistic.CountStatistic; /** * @author: lanbo <br> * @version: 1.0 <br> * @date: 2012-7-20 */ public class DefaultActorManager implements ActorManager { /** 是否已经完成初始化 */ volatile boolean initialized = false; /** 锁对象 */ Object lock = new Object(); /** 线程组标识 */ static int groupCount = 0; /** 设置当前ActorManager分配多少条线程处理消息 */ public int threadCount = Constants.DEFAULT_ACTOR_THREAD_COUNT; /** 实际使用线程计数 */ int realUsedThreadCount = 0; /** 每条线程运行接受最大消息数(队列中) ,如果为0,则表示没有限制 */ public long maximumMessageSize = 0; /** */ public RejectedMessageHandler rejectedMessageHandler = RejectedMessageHandlers.discardPolicy(); /** 线程组 */ ThreadGroup threadGroup; /** 随机数生成器 */ Random random = new Random(); /** 执行线程 */ ThreadWrapper[] threads; /** Actor集合 */ ConcurrentHashMap<String, Actor> actors = new ConcurrentHashMap<String, Actor>(); public Class<? extends MessageQueue<?>> messageQueueType = MemMessageQueue.class; /** 当消息没有任何Actor处理时,由NoneMessageActor负责执行 */ public AbstractActor noneMessageActor = new NoneMessageActor(); { noneMessageActor.setManager(this); } /** ActorManager状态 */ boolean running = false, terminated = false; public Logger logger; // //////////////////////////////统计计数器//////////////////////////////////////////////////////////// CountStatistic totalStat = Statistics.getCountStat("TOTAL-ACTOR"); CountStatistic rejectStat = Statistics.getCountStat("REJECT-ACTOR"); Map<Integer, CountStatistic> actorStat = new HashMap<Integer, CountStatistic>(); // /////////////////////////////////////////////////////////////////////////////////////////////////// @Override public void initialize() { this.initialize(null); } @Override public void initialize(Map<String, Object> options) { synchronized (lock) { if (initialized) { logger.warn("DefaultActorManager has been initialized. Won't initialize again!"); return; } initialized = running = true; terminated = false; // 计算需要分配多少条线程 int count = getThreadCount(options); threadGroup = new ThreadGroup("ActorManager-ThreadGroup-" + groupCount++); threads = new ThreadWrapper[count]; // 创建线程 for (int i = 0; i < count; i++) { createThread(i); } // 启动线程 for (Thread t : threads) { t.start(); } // TODO 统计计数线程 new Timer().schedule(new TimerTask() { @Override public void run() { for (ThreadWrapper th : threads) { MessageRedcapRunnable runnable = (MessageRedcapRunnable) th.getRunnable(); int size = runnable.getQueue().size(); String msg = "[" + th.getName() + "] message in queue: " + size; logger.warn(msg); } } }, 10 * 60 * 1000, 10 * 60 * 1000); } } /** * 创建消息处理线程 * * @param i */ private Thread createThread(int i) { ThreadWrapper t = null; if (threads[i] != null) { throw new IllegalStateException("already exists: Actor-" + i); } MessageRedcapRunnable runnable = new MessageRedcapRunnable(maximumMessageSize, new MessageRedcapCallback() { @Override public void execute(MessageWrapper message) { Message realMessage = message.getMessage(); boolean processed = false; // TODO 对Mode、Target做分类统计 switch (message.getMode()) { case BROAD_CAST: { for (Actor actor : actors.values()) { ((AbstractActor) actor).process(realMessage); processed = true; } break; } case PEER_2_MULTI: { List<String> targets = message.getTargets(); if (targets == null || targets.size() == 0) break; for (String name : actors.keySet()) { if (targets.contains(name)) { ((AbstractActor) actors.get(name)).process(realMessage); processed = true; } } break; } case PEER_2_PEER: { String target = message.getTargetName(); if (target == null) break; Actor actor = actors.get(target); if (actor == null) break; ((AbstractActor) actor).process(realMessage); processed = true; break; } } if (!processed) { noneMessageActor.process(realMessage); } } }); actorStat.put(i, Statistics.getCountStat("Actor-" + i)); t = new ThreadWrapper(threadGroup, runnable, "Actor-" + i); t.setDaemon(true); t.setPriority(getThreadPriority()); threads[i] = t; realUsedThreadCount++; return t; } /** * 获取线程优先级 * * @return */ private int getThreadPriority() { return Math.max(Thread.MIN_PRIORITY, Thread.currentThread().getPriority() - 1); } /** * 注意,这里可能会抛出异常,如果指定的参数类型不合法时。 * * @param options * @return */ private int getThreadCount(Map<String, Object> options) { Object xcount = options != null ? options.get(Constants.OPTION_KEY_THREAD_COUNT) : null; if (xcount == null) { return threadCount; } else if (xcount instanceof Integer) { return (Integer) xcount; } else if (xcount instanceof Long) { return ((Long) xcount).intValue(); } else if (xcount instanceof Double) { return ((Double) xcount).intValue(); } else if (xcount instanceof String) { return Integer.parseInt((String) xcount); } else { throw new IllegalArgumentException("thread count is not correctly setted!"); } } @Override public void terminateAndWait() { // TODO } @Override public void terminate() { terminated = !(running = false); // 将所有线程都停止掉,但是线程还会处理掉没有处理完的消息 for (ThreadWrapper th : threads) { Runnable runnable = th.getRunnable(); if (runnable instanceof MessageRedcapRunnable) { ((MessageRedcapRunnable) runnable).setRunning(false); } else { th.interrupt(); } } for (Actor actor : actors.values()) { actor.deactivate(); } } @Override public Actor createActor(Class<? extends Actor> clazz) { return createActor(clazz, null); } @Override public Actor createActor(Class<? extends Actor> clazz, Map<String, Object> options) { if (!AbstractActor.class.isAssignableFrom(clazz)) { throw new UnsupportedOperationException("actor must be typeof AbstractActor"); } Actor actor = null; try { actor = clazz.newInstance(); } catch (Exception e) { Throwables.propagate(e); } synchronized (actors) { if (!actors.containsKey(actor.getName())) { try { ((AbstractActor) actor).setManager(this); actors.put(actor.getName(), actor); } catch (Exception e) { throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException("mapped exception: " + e, e); } } else { throw new IllegalArgumentException("name already in use: " + actor.getName()); } } return actor; } @Override public boolean startActor(Actor actor) { checkActor(actor); String name = actor.getName(); synchronized (actors) { if (actors.containsKey(name)) { throw new IllegalStateException("actor [" + name + "] already started"); } actor.activate(); actors.put(name, actor); } return true; } @Override public boolean detachActor(String name) { synchronized (actors) { if (actors.containsKey(name)) { Actor actor = actors.get(name); if (((AbstractActor) actor).getManager() != this) { throw new IllegalStateException("actor not owned by this manager"); } actor.deactivate(); actors.remove(name); return true; } else { return false; } } } @Override public boolean detachActor(Actor actor) { checkActor(actor); detachActor(actor.getName()); return false; } private void checkActor(Actor actor) { if (!(actor instanceof AbstractActor)) { throw new UnsupportedOperationException("actor must be typeof AbstractActor"); } if (((AbstractActor) actor).getManager() != this) { throw new IllegalStateException("actor not owned by this manager"); } } @Override public Actor createAndStartActor(Class<? extends Actor> clazz) { return createAndStartActor(clazz, null); } @Override public Actor createAndStartActor(Class<? extends Actor> clazz, Map<String, Object> options) { Actor actor = createActor(clazz, options); startActor(actor); return actor; } @Override public int broadcast(Message message, Actor from) { checkActorManagerState(); MessageWrapper wrapper = new MessageWrapper(); wrapper.setMessage(message); if (from == null) { wrapper.setSourceName("unknown-actor"); } else { wrapper.setSourceName(from.getName()); } wrapper.setMode(MessageWrapper.SpreadMode.BROAD_CAST); addMessageToQueue(wrapper); return 1; } @Override public int send(Message message, Actor sourceActor, String targetName) { checkActorManagerState(); MessageWrapper wrapper = new MessageWrapper(); wrapper.setMessage(message); if (sourceActor == null) { wrapper.setSourceName("unknown-actor"); } else { wrapper.setSourceName(sourceActor.getName()); } wrapper.setTargetName(targetName); wrapper.setMode(MessageWrapper.SpreadMode.PEER_2_PEER); addMessageToQueue(wrapper); return 1; } private void checkActorManagerState() { if (terminated || !running) { throw new IllegalStateException("ActorManager is terminated or not running!"); } } @Override public int send(Message message, Actor sourceActor, String[] targetNames) { checkActorManagerState(); MessageWrapper wrapper = new MessageWrapper(); wrapper.setMessage(message); if (sourceActor == null) { wrapper.setSourceName("unknown-actor"); } else { wrapper.setSourceName(sourceActor.getName()); } wrapper.setTargets(Lists.newArrayList(targetNames)); wrapper.setMode(MessageWrapper.SpreadMode.PEER_2_MULTI); addMessageToQueue(wrapper); return 1; } @Override public int send(Message message, Actor sourceActor, Collection<String> targetNames) { String[] list = (String[]) targetNames.toArray(); return send(message, sourceActor, list); } /** * 增加消息到队列 * * @param message */ protected void addMessageToQueue(MessageWrapper message) { int hash = message.hashCode() % realUsedThreadCount; if (threads.length < hash) { hash %= threads.length; } ThreadWrapper threadWrapper = threads[hash]; Runnable runnable = threadWrapper.getRunnable(); Preconditions.checkArgument(runnable instanceof MessageRedcapRunnable, "thread's target is not typeof MessageRedcapRunnable"); boolean succ = ((MessageRedcapRunnable) runnable).addMessage(message); if (!succ && rejectedMessageHandler != null) { rejectedMessageHandler.reject(message, threadWrapper); rejectStat.incr(); } totalStat.incr(); actorStat.get(hash).incr(); } /** * 测试Random是否分布均匀 0 -> 100055 1 -> 100196 2 -> 99803 3 -> 100186 4 -> 100040 * 5 -> 99969 6 -> 100198 7 -> 99653 8 -> 99955 9 -> 99945 */ public static void main(String[] args) { Random random = new Random(); Multiset<Integer> stat = HashMultiset.<Integer> create(); for (int i = 0; i < 1000000; i++) { int nextInt = random.nextInt(10); stat.add(nextInt); } for (int v : stat.elementSet()) { System.err.println(v + " -> " + stat.count(v)); } } public ThreadWrapper[] getThreads() { return threads; } }