diff --git a/src/org/apollo/game/GameService.java b/src/org/apollo/game/GameService.java index 7424b81a..02fd3f73 100644 --- a/src/org/apollo/game/GameService.java +++ b/src/org/apollo/game/GameService.java @@ -20,12 +20,11 @@ import org.apollo.io.MessageHandlerChainSetParser; import org.apollo.login.LoginService; import org.apollo.net.session.GameSession; import org.apollo.util.MobRepository; +import org.apollo.util.ThreadUtil; import org.apollo.util.xml.XmlNode; import org.apollo.util.xml.XmlParser; import org.xml.sax.SAXException; -import com.google.common.util.concurrent.ThreadFactoryBuilder; - /** * The {@link GameService} class schedules and manages the execution of the {@link GamePulseHandler} class. * @@ -52,7 +51,7 @@ public final class GameService extends Service { /** * The scheduled executor service. */ - private final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder().setNameFormat("GameService").build()); + private final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(ThreadUtil.build("GameService")); /** * The {@link ClientSynchronizer}. diff --git a/src/org/apollo/game/sync/ParallelClientSynchronizer.java b/src/org/apollo/game/sync/ParallelClientSynchronizer.java index 54b6b202..1fac73e1 100644 --- a/src/org/apollo/game/sync/ParallelClientSynchronizer.java +++ b/src/org/apollo/game/sync/ParallelClientSynchronizer.java @@ -6,7 +6,6 @@ import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Phaser; -import java.util.concurrent.ThreadFactory; import org.apollo.game.GameService; import org.apollo.game.message.impl.RegionUpdateMessage; @@ -22,8 +21,7 @@ import org.apollo.game.sync.task.PreNpcSynchronizationTask; import org.apollo.game.sync.task.PrePlayerSynchronizationTask; import org.apollo.game.sync.task.SynchronizationTask; import org.apollo.util.MobRepository; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.apollo.util.ThreadUtil; /** * An implementation of {@link ClientSynchronizer} which runs in a thread pool. A {@link Phaser} is used to ensure that @@ -49,12 +47,10 @@ public final class ParallelClientSynchronizer extends ClientSynchronizer { /** * Creates the parallel client synchronizer backed by a thread pool with a number of threads equal to the number of - * processing cores available (this is found by the {@link Runtime#availableProcessors()} method. + * processing cores available (this is found by the {@link ThreadUtil#AVAILABLE_PROCESSORS} method. */ public ParallelClientSynchronizer() { - int processors = Runtime.getRuntime().availableProcessors(); - ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("ClientSynchronizer").build(); - executor = Executors.newFixedThreadPool(processors, factory); + executor = Executors.newFixedThreadPool(ThreadUtil.AVAILABLE_PROCESSORS, ThreadUtil.build("ClientSynchronizer")); } @Override diff --git a/src/org/apollo/util/ThreadUtil.java b/src/org/apollo/util/ThreadUtil.java new file mode 100644 index 00000000..d31df05f --- /dev/null +++ b/src/org/apollo/util/ThreadUtil.java @@ -0,0 +1,136 @@ +package org.apollo.util; + +import static com.google.common.base.Preconditions.checkArgument; + +import java.lang.Thread.UncaughtExceptionHandler; +import java.util.Objects; +import java.util.concurrent.ThreadFactory; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +/** + * A static utility class which provides ease of use functionality for {@link Thread}s + * + * @author Ryley Kimmel + */ +public final class ThreadUtil { + + /** + * Returns the amount of available processors available to the Java virtual machine. + */ + public static final int AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors(); + + /** + * A {@link Logger} used to debug messages to the console. + */ + private static final Logger LOGGER = Logger.getLogger(ThreadUtil.class.getSimpleName()); + + /** + * The default {@link UncaughtExceptionHandler} which raises an error from the logger with the exception and name of + * the specified thread the exception occurred in. + */ + private static final UncaughtExceptionHandler DEFAULT_EXCEPTION_HANDLER = (thread, exception) -> LOGGER.log(Level.SEVERE, "Exception occured in thread " + thread.getName(), exception); + + /** + * Builds a {@link ThreadFactory} using the specified {@code String} name-format, {@link ThreadPriority} and + * {@link UncaughtExceptionHandler}. + * + * @param name The name-format used when creating threads, may not be {@code null}. + * @param priority The priority used when creating threads, may not be {@code null}. + * @param handler The {@link UncaughtExceptionHandler} used when creating threads, may not be {@code null}. + * @return A new {@link ThreadFactory} from the specified parameters, never {@code null}. + */ + public static ThreadFactory build(String name, ThreadPriority priority, UncaughtExceptionHandler handler) { + Objects.requireNonNull(priority); + + ThreadFactoryBuilder bldr = new ThreadFactoryBuilder(); + bldr.setNameFormat(name); + bldr.setPriority(priority.getValue()); + bldr.setUncaughtExceptionHandler(handler); + return bldr.build(); + } + + /** + * Builds a {@link ThreadFactory} using the specified {@code String} name-format, {@link ThreadPriority} and the + * default {@link UncaughtExceptionHandler}. + * + * @param name The name-format used when creating threads, may not be {@code null}. + * @param priority The priority used when creating threads, may not be {@code null}. + * @return A new {@link ThreadFactory} from the specified parameters, never {@code null}. + * @see {@link #DEFAULT_EXCEPTION_HANDLER} + */ + public static ThreadFactory build(String name, ThreadPriority priority) { + return build(name, priority, DEFAULT_EXCEPTION_HANDLER); + } + + /** + * Builds a {@link ThreadFactory} using the specified {@code String} name-format, normal thread priority and the + * default {@link UncaughtExceptionHandler}. + * + * @param name The name-format used when creating threads, may not be {@code null}. + * @return A new {@link ThreadFactory} from the specified parameters, never {@code null}. + * @see {@link #DEFAULT_EXCEPTION_HANDLER} + * @see {@link ThreadPriority#NORMAL_PRIORITY} + */ + public static ThreadFactory build(String name) { + return build(name, ThreadPriority.NORMAL_PRIORITY, DEFAULT_EXCEPTION_HANDLER); + } + + /** + * An enumeration representing the priority of a {@link Thread}. + * + * @author Ryley Kimmel + */ + public enum ThreadPriority { + + /** + * Represents the minimum priority of a thread. + */ + MINIMUM_PRIORITY(1), + + /** + * Represents the normal priority of a thread. + */ + NORMAL_PRIORITY(5), + + /** + * Represents the maximum priority of a thread. + */ + MAXIMUM_PRIORITY(10); + + /** + * The value of this thread priority. + */ + private final int value; + + /** + * Constructs a new {@link ThreadPriority} with the specified value. + * + * @param value The value of this thread priority, must be within the bounds of {@link Thread#MIN_PRIORITY} and + * {@link Thread#MAX_PRIORITY}. + */ + private ThreadPriority(int value) { + // fail-fast for invalid priority values + checkArgument(value >= Thread.MIN_PRIORITY, "Thread priority (%s) must be >= %s", value, Thread.MIN_PRIORITY); + checkArgument(value <= Thread.MAX_PRIORITY, "Thread priority (%s) must be <= %s", value, Thread.MAX_PRIORITY); + + this.value = value; + } + + /** + * Returns the value of this thread priority. + */ + public final int getValue() { + return value; + } + } + + /** + * Prevents the default-public constructor to discourage instantiation of this class. + */ + private ThreadUtil() { + } + +} \ No newline at end of file