/** * This file is part of aion-emu <aion-emu.com>. * * aion-emu is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * aion-emu is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with aion-emu. If not, see <http://www.gnu.org/licenses/>. */ package com.aionemu.loginserver.utils; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.apache.log4j.Logger; import com.aionemu.commons.network.DisconnectionTask; import com.aionemu.commons.network.DisconnectionThreadPool; import com.aionemu.commons.utils.ScheduledThreadPoolExecutorAE; /** * @author -Nemesiss- */ public class ThreadPoolManager implements DisconnectionThreadPool { /** * Logger for this class */ private static final Logger log = Logger.getLogger(ThreadPoolManager.class); /** * Instance of ThreadPoolManager */ private static ThreadPoolManager instance = new ThreadPoolManager(); /** * STPE for normal scheduled tasks */ private ScheduledThreadPoolExecutorAE scheduledThreadPool; /** * STPE for disconnection tasks */ private ScheduledThreadPoolExecutorAE disconnectionScheduledThreadPool; /** * TPE for execution of gameserver client packets */ private ThreadPoolExecutor gameServerPacketsThreadPool; /** * @return ThreadPoolManager instance. */ public static ThreadPoolManager getInstance() { return instance; } /** * Constructor. */ private ThreadPoolManager() { scheduledThreadPool = new ScheduledThreadPoolExecutorAE(4, new PriorityThreadFactory("ScheduledThreadPool", Thread.NORM_PRIORITY)); scheduledThreadPool.setRemoveOnCancelPolicy(true); disconnectionScheduledThreadPool = new ScheduledThreadPoolExecutorAE(4, new PriorityThreadFactory( "ScheduledThreadPool", Thread.NORM_PRIORITY)); disconnectionScheduledThreadPool.setRemoveOnCancelPolicy(true); gameServerPacketsThreadPool = new ThreadPoolExecutor(4, Integer.MAX_VALUE, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new PriorityThreadFactory("Game Server Packet Pool", Thread.NORM_PRIORITY + 3)); } /** * Schedule * * @param <T> * @param r * @param delay * @return ScheduledFuture */ @SuppressWarnings("unchecked") public <T extends Runnable> ScheduledFuture<T> schedule(T r, long delay) { try { if (delay < 0) delay = 0; return (ScheduledFuture<T>) scheduledThreadPool.schedule(r, delay, TimeUnit.MILLISECONDS); } catch (RejectedExecutionException e) { return null; /* shutdown, ignore */ } } /** * Schedule at fixed rate * * @param <T> * @param r * @param initial * @param delay * @return ScheduledFuture */ @SuppressWarnings("unchecked") public <T extends Runnable> ScheduledFuture<T> scheduleAtFixedRate(T r, long initial, long delay) { try { if (delay < 0) delay = 0; if (initial < 0) initial = 0; return (ScheduledFuture<T>) scheduledThreadPool.scheduleAtFixedRate(r, initial, delay, TimeUnit.MILLISECONDS); } catch (RejectedExecutionException e) { return null; } } /** * Executes Runnable - GameServer Client packet. * * @param pkt */ public void executeGsPacket(Runnable pkt) { gameServerPacketsThreadPool.execute(pkt); } /** * {@inheritDoc} */ @Override public final void scheduleDisconnection(DisconnectionTask dt, long delay) { if (delay < 0) delay = 0; scheduledThreadPool.schedule(dt, delay, TimeUnit.MILLISECONDS); } /** * {@inheritDoc} */ @Override public void waitForDisconnectionTasks() { try { disconnectionScheduledThreadPool.shutdown(); disconnectionScheduledThreadPool.awaitTermination(6, TimeUnit.MINUTES); } catch (Exception e) { } } /** * PriorityThreadFactory creating new threads for ThreadPoolManager * */ private class PriorityThreadFactory implements ThreadFactory { /** * Priority of new threads */ private int prio; /** * Thread group name */ private String name; /** * Number of created threads */ private AtomicInteger threadNumber = new AtomicInteger(1); /** * ThreadGroup for created threads */ private ThreadGroup group; /** * Constructor. * * @param name * @param prio */ public PriorityThreadFactory(String name, int prio) { this.prio = prio; this.name = name; group = new ThreadGroup(this.name); } /** * {@inheritDoc} */ @Override public Thread newThread(Runnable r) { Thread t = new Thread(group, r); t.setName(name + "-" + threadNumber.getAndIncrement()); t.setPriority(prio); t.setUncaughtExceptionHandler(new ThreadUncaughtExceptionHandler()); return t; } } /** * Shutdown all thread pools. */ public void shutdown() { try { scheduledThreadPool.shutdown(); gameServerPacketsThreadPool.shutdown(); scheduledThreadPool.awaitTermination(2, TimeUnit.SECONDS); gameServerPacketsThreadPool.awaitTermination(2, TimeUnit.SECONDS); log.info("All ThreadPools are now stopped"); } catch (InterruptedException e) { log.error("Can't shutdown ThreadPoolManager", e); } } }