/** * Constructs a new {@link SingleThreadScheduler}. No threads will start until the first task * is provided. * * @param defaultPriority Default priority for tasks which are submitted without any specified priority * @param maxWaitForLowPriorityInMs time low priority tasks to wait if there are high priority tasks ready to run * @param daemonThread {@code true} if scheduler thread should be a daemon thread */ public SingleThreadScheduler(TaskPriority defaultPriority, long maxWaitForLowPriorityInMs, boolean daemonThread) { this(defaultPriority, maxWaitForLowPriorityInMs, new ConfigurableThreadFactory(SingleThreadScheduler.class.getSimpleName() + "-", true, daemonThread, Thread.NORM_PRIORITY, null, null)); }
@Override public Thread newThread(Runnable r) { Thread result = super.newThread(r); if (Clock.lastKnownForwardProgressingMillis() - lastCleanupTime > REFERENCE_QUEUE_CHECK_INTERVAL_MILLIS) { // not designed to be a memory barrier, can be done in parallel, just dont want it done too much lastCleanupTime = Clock.lastKnownForwardProgressingMillis(); Iterator<WeakReference<Thread>> it = threads.iterator(); while (it.hasNext()) { if (it.next().get() == null) { it.remove(); } } } threads.add(new WeakReference<>(result)); return result; } }
/** * Constructs a new {@link SingleThreadScheduler}. No threads will start until the first task * is provided. * * @param defaultPriority Default priority for tasks which are submitted without any specified priority * @param maxWaitForLowPriorityInMs time low priority tasks to wait if there are high priority tasks ready to run * @param daemonThread {@code true} if scheduler thread should be a daemon thread */ public SingleThreadScheduler(TaskPriority defaultPriority, long maxWaitForLowPriorityInMs, boolean daemonThread) { this(defaultPriority, maxWaitForLowPriorityInMs, new ConfigurableThreadFactory(SingleThreadScheduler.class.getSimpleName() + "-", true, daemonThread, Thread.NORM_PRIORITY, null, null)); }
@Override public Thread newThread(Runnable r) { Thread result = super.newThread(r); if (Clock.lastKnownForwardProgressingMillis() - lastCleanupTime > REFERENCE_QUEUE_CHECK_INTERVAL_MILLIS) { // not designed to be a memory barrier, can be done in parallel, just dont want it done too much lastCleanupTime = Clock.lastKnownForwardProgressingMillis(); Iterator<WeakReference<Thread>> it = threads.iterator(); while (it.hasNext()) { if (it.next().get() == null) { it.remove(); } } } threads.add(new WeakReference<>(result)); return result; } }
/** * Constructs a new thread pool, though threads will be lazily started as it has tasks ready to * run. This provides the extra parameters to tune what tasks submitted without a priority * will be scheduled as. As well as the maximum wait for low priority tasks. * * @param poolSize Thread pool size that should be maintained * @param defaultPriority Default priority for tasks which are submitted without any specified priority * @param maxWaitForLowPriorityInMs time low priority tasks to wait if there are high priority tasks ready to run * @param useDaemonThreads {@code true} if newly created threads should be daemon */ public PriorityScheduler(int poolSize, TaskPriority defaultPriority, long maxWaitForLowPriorityInMs, boolean useDaemonThreads) { this(poolSize, defaultPriority, maxWaitForLowPriorityInMs, new ConfigurableThreadFactory(PriorityScheduler.class.getSimpleName() + "-", true, useDaemonThreads, Thread.NORM_PRIORITY, null, null)); }
@Override public Thread newThread(final Runnable r) { Runnable livingRunnable = new Runnable() { @Override public void run() { try { r.run(); } finally { try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException e) { // let thread exit return; } } } }; Thread result = parentFactory.newThread(livingRunnable); synchronized (toKillThreads) { toKillThreads.add(result); } result.start(); return result; }
/** * Constructs a new {@link UnfairExecutor} with a provided thread count. * <p> * Possible built in stripe generators for use would be {@link AtomicStripeGenerator} or * {@link TaskHashXorTimeStripeGenerator}. * * @param threadCount Number of threads, recommended to be a prime number * @param useDaemonThreads {@code true} if created threads should be daemon * @param stripeGenerator Generator for figuring out how a task is assigned to a thread */ public UnfairExecutor(int threadCount, boolean useDaemonThreads, TaskStripeGenerator stripeGenerator) { this(threadCount, new ConfigurableThreadFactory(UnfairExecutor.class.getSimpleName() + "-", true, useDaemonThreads, Thread.NORM_PRIORITY, null, null), stripeGenerator); }
@Test public void emptyConstructorTest() { ThreadFactory defaultFactory = makeThreadFactory(); ConfigurableThreadFactory ctf = makeThreadFactory(); Thread defaultThread = defaultFactory.newThread(DoNothingRunnable.instance()); Thread configurableThread = ctf.newThread(DoNothingRunnable.instance()); String defaultName = defaultThread.getName(); String configurableName = configurableThread.getName(); int firstDashIndex = defaultName.indexOf('-'); int secondDashIndex = defaultName.indexOf('-', firstDashIndex + 1); String defaultSantaizedName = defaultName.substring(0, firstDashIndex) + defaultName.substring(secondDashIndex); firstDashIndex = configurableName.indexOf('-'); secondDashIndex = configurableName.indexOf('-', firstDashIndex + 1); String configurableSantaizedName = configurableName.substring(0, firstDashIndex) + configurableName.substring(secondDashIndex); assertEquals(defaultSantaizedName, configurableSantaizedName); assertEquals(defaultThread.isDaemon(), configurableThread.isDaemon()); assertEquals(defaultThread.getPriority(), configurableThread.getPriority()); assertTrue(defaultThread.getUncaughtExceptionHandler() == configurableThread.getUncaughtExceptionHandler()); assertTrue(defaultThread.getThreadGroup() == configurableThread.getThreadGroup()); assertFalse(configurableThread.isAlive()); }
/** * Constructs a new thread pool, though threads will be lazily started as it has tasks ready to * run. This provides the extra parameters to tune what tasks submitted without a priority * will be scheduled as. As well as the maximum wait for low priority tasks. * * @param poolSize Thread pool size that should be maintained * @param defaultPriority Default priority for tasks which are submitted without any specified priority * @param maxWaitForLowPriorityInMs time low priority tasks to wait if there are high priority tasks ready to run * @param useDaemonThreads {@code true} if newly created threads should be daemon */ public PriorityScheduler(int poolSize, TaskPriority defaultPriority, long maxWaitForLowPriorityInMs, boolean useDaemonThreads) { this(poolSize, defaultPriority, maxWaitForLowPriorityInMs, new ConfigurableThreadFactory(PriorityScheduler.class.getSimpleName() + "-", true, useDaemonThreads, Thread.NORM_PRIORITY, null, null)); }
@Test public void setPrefixWithPoolIdTest() { String poolPrefix = StringUtils.makeRandomString(5); ConfigurableThreadFactory ctf1 = makeThreadFactory(poolPrefix, true); ConfigurableThreadFactory ctf2 = makeThreadFactory(poolPrefix, true); assertTrue(ctf1.threadNamePrefix.contains(poolPrefix)); assertFalse(ctf1.threadNamePrefix.equals(ctf2.threadNamePrefix)); Thread t = ctf1.newThread(DoNothingRunnable.instance()); assertTrue(t.getName().contains(ctf1.threadNamePrefix)); }
/** * Constructs a new {@link UnfairExecutor} with a provided thread count. * <p> * Possible built in stripe generators for use would be {@link AtomicStripeGenerator} or * {@link TaskHashXorTimeStripeGenerator}. * * @param threadCount Number of threads, recommended to be a prime number * @param useDaemonThreads {@code true} if created threads should be daemon * @param stripeGenerator Generator for figuring out how a task is assigned to a thread */ public UnfairExecutor(int threadCount, boolean useDaemonThreads, TaskStripeGenerator stripeGenerator) { this(threadCount, new ConfigurableThreadFactory(UnfairExecutor.class.getSimpleName() + "-", true, useDaemonThreads, Thread.NORM_PRIORITY, null, null), stripeGenerator); }
@Test public void setPrefixWithoutPoolIdTest() { String poolPrefix = StringUtils.makeRandomString(5); ConfigurableThreadFactory ctf1 = makeThreadFactory(poolPrefix, false); ConfigurableThreadFactory ctf2 = makeThreadFactory(poolPrefix, false); assertTrue(ctf1.threadNamePrefix.contains(poolPrefix)); assertTrue(ctf1.threadNamePrefix.equals(ctf2.threadNamePrefix)); Thread t = ctf1.newThread(DoNothingRunnable.instance()); assertTrue(t.getName().contains(ctf1.threadNamePrefix)); }
/** * Constructs a new {@link SingleThreadScheduler}. No threads will start until the first task * is provided. * * @param defaultPriority Default priority for tasks which are submitted without any specified priority * @param maxWaitForLowPriorityInMs time low priority tasks to wait if there are high priority tasks ready to run * @param daemonThread {@code true} if scheduler thread should be a daemon thread * @param maxStatisticWindowSize maximum number of samples to keep internally * @param accurateTime {@code true} to ensure that delays and durations are not under reported */ public SingleThreadSchedulerStatisticTracker(TaskPriority defaultPriority, long maxWaitForLowPriorityInMs, boolean daemonThread, int maxStatisticWindowSize, boolean accurateTime) { this(defaultPriority, maxWaitForLowPriorityInMs, new ConfigurableThreadFactory(SingleThreadScheduler.class.getSimpleName() + "-", true, daemonThread, Thread.NORM_PRIORITY, null, null), maxStatisticWindowSize, accurateTime); }
@Test public void useDaemonThreadTest() { ConfigurableThreadFactory ctfFalse = makeThreadFactory(false); ConfigurableThreadFactory ctfTrue = makeThreadFactory(true); Thread t; assertFalse(ctfFalse.useDaemonThreads); t = ctfFalse.newThread(DoNothingRunnable.instance()); assertFalse(t.isDaemon()); assertTrue(ctfTrue.useDaemonThreads); t = ctfTrue.newThread(DoNothingRunnable.instance()); assertTrue(t.isDaemon()); }
/** * Constructs a new {@link SingleThreadScheduler}. No threads will start until the first task * is provided. * * @param defaultPriority Default priority for tasks which are submitted without any specified priority * @param maxWaitForLowPriorityInMs time low priority tasks to wait if there are high priority tasks ready to run * @param daemonThread {@code true} if scheduler thread should be a daemon thread * @param maxStatisticWindowSize maximum number of samples to keep internally * @param accurateTime {@code true} to ensure that delays and durations are not under reported */ public SingleThreadSchedulerStatisticTracker(TaskPriority defaultPriority, long maxWaitForLowPriorityInMs, boolean daemonThread, int maxStatisticWindowSize, boolean accurateTime) { this(defaultPriority, maxWaitForLowPriorityInMs, new ConfigurableThreadFactory(SingleThreadScheduler.class.getSimpleName() + "-", true, daemonThread, Thread.NORM_PRIORITY, null, null), maxStatisticWindowSize, accurateTime); }
@Test public void setPriorityTest() { int priority = Thread.NORM_PRIORITY + 1; ConfigurableThreadFactory ctf = makeThreadFactory(priority); assertEquals(priority, ctf.threadPriority); Thread t = ctf.newThread(DoNothingRunnable.instance()); assertEquals(priority, t.getPriority()); }
/** * Constructs a new thread pool, though no threads will be started till it accepts it's first * request. This provides the extra parameters to tune what tasks submitted without a priority * will be scheduled as. As well as the maximum wait for low priority tasks. The longer low * priority tasks wait for a worker, the less chance they will have to create a thread. But it * also makes low priority tasks execution time less predictable. * * @param poolSize Thread pool size that should be maintained * @param defaultPriority priority to give tasks which do not specify it * @param maxWaitForLowPriorityInMs time low priority tasks wait for a worker * @param useDaemonThreads {@code true} if newly created threads should be daemon * @param maxStatisticWindowSize maximum number of samples to keep internally * @param accurateTime {@code true} to ensure that delays and durations are not under reported */ public PrioritySchedulerStatisticTracker(int poolSize, TaskPriority defaultPriority, long maxWaitForLowPriorityInMs, boolean useDaemonThreads, int maxStatisticWindowSize, boolean accurateTime) { this(poolSize, defaultPriority, maxWaitForLowPriorityInMs, new ConfigurableThreadFactory(PrioritySchedulerStatisticTracker.class.getSimpleName() + "-", true, useDaemonThreads, Thread.NORM_PRIORITY, null, null), maxStatisticWindowSize, accurateTime); }
@Test public void setExceptionHandlerTest() { TestExceptionHandler teh = new TestExceptionHandler(); ConfigurableThreadFactory ctf = makeThreadFactory(teh); assertEquals(teh, ctf.defaultThreadlyExceptionHandler); final AtomicReference<ExceptionHandler> ehi = new AtomicReference<>(null); TestRunnable tr = new TestRunnable() { @Override public void handleRunStart() { ehi.set(ExceptionUtils.getExceptionHandler()); } }; Thread t = ctf.newThread(tr); t.start(); tr.blockTillFinished(); assertTrue(ehi.get() == teh); } }
/** * Constructs a new thread pool, though no threads will be started till it accepts it's first * request. This provides the extra parameters to tune what tasks submitted without a priority * will be scheduled as. As well as the maximum wait for low priority tasks. The longer low * priority tasks wait for a worker, the less chance they will have to create a thread. But it * also makes low priority tasks execution time less predictable. * * @param poolSize Thread pool size that should be maintained * @param defaultPriority priority to give tasks which do not specify it * @param maxWaitForLowPriorityInMs time low priority tasks wait for a worker * @param useDaemonThreads {@code true} if newly created threads should be daemon * @param maxStatisticWindowSize maximum number of samples to keep internally * @param accurateTime {@code true} to ensure that delays and durations are not under reported */ public PrioritySchedulerStatisticTracker(int poolSize, TaskPriority defaultPriority, long maxWaitForLowPriorityInMs, boolean useDaemonThreads, int maxStatisticWindowSize, boolean accurateTime) { this(poolSize, defaultPriority, maxWaitForLowPriorityInMs, new ConfigurableThreadFactory(PrioritySchedulerStatisticTracker.class.getSimpleName() + "-", true, useDaemonThreads, Thread.NORM_PRIORITY, null, null), maxStatisticWindowSize, accurateTime); }
@Test public void setUncaughtExceptionHandlerTest() { TestUncaughtExceptionHandler ueh = new TestUncaughtExceptionHandler(); ConfigurableThreadFactory ctf = makeThreadFactory(ueh); assertEquals(ueh, ctf.defaultUncaughtExceptionHandler); Thread t = ctf.newThread(DoNothingRunnable.instance()); assertEquals(ueh, t.getUncaughtExceptionHandler()); }