callable, final long delay, final TimeUnit unit) {
return delegate.schedule(callable, delay, unit);
}
public ScheduledFuture> scheduleAtFixedRate(final Runnable command, final long initialDelay, final long period, final TimeUnit unit) {
return delegate.scheduleAtFixedRate(command, initialDelay, period, unit);
}
public ScheduledFuture> scheduleWithFixedDelay(final Runnable command, final long initialDelay, final long delay, final TimeUnit unit) {
return delegate.scheduleWithFixedDelay(command, initialDelay, delay, unit);
}
} jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/DiscardingExecutor.java 0000664 0000000 0000000 00000002103 13615100441 0027730 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.util.concurrent.Executor;
class DiscardingExecutor implements Executor {
static final DiscardingExecutor INSTANCE = new DiscardingExecutor();
private DiscardingExecutor() {
}
public void execute(final Runnable command) {
// nothing
}
public String toString() {
return "Discarding executor";
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/EnhancedQueueExecutor.java 0000664 0000000 0000000 00000265510 13615100441 0030410 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.lang.Thread.currentThread;
import static java.security.AccessController.doPrivileged;
import static java.security.AccessController.getContext;
import static java.util.concurrent.locks.LockSupport.*;
import static org.jboss.threads.JBossExecutors.unsafe;
import java.lang.management.ManagementFactory;
import java.security.AccessControlContext;
import java.security.PrivilegedAction;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.LongAdder;
import java.util.concurrent.locks.Lock;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import org.jboss.threads.management.ManageableThreadPoolExecutorService;
import org.jboss.threads.management.StandardThreadPoolMXBean;
import org.wildfly.common.Assert;
import org.wildfly.common.lock.ExtendedLock;
import org.wildfly.common.lock.Locks;
import org.wildfly.common.lock.SpinLock;
/**
* A task-or-thread queue backed thread pool executor service. Tasks are added in a FIFO manner, and consumers in a LIFO manner.
* Threads are only ever created in the event that there are no idle threads available to service a task, which, when
* combined with the LIFO-based consumer behavior, means that the thread pool will generally trend towards the minimum
* necessary size. In addition, the optional {@linkplain #setGrowthResistance(float) growth resistance feature} can
* be used to further govern the thread pool size.
*
* New instances of this thread pool are created by constructing and configuring a {@link Builder} instance, and calling
* its {@link Builder#build() build()} method.
*
* @author David M. Lloyd
*/
public final class EnhancedQueueExecutor extends EnhancedQueueExecutorBase6 implements ManageableThreadPoolExecutorService {
private static final Thread[] NO_THREADS = new Thread[0];
static {
Version.getVersionString();
}
/*
┌──────────────────────────┐
│ Explanation of operation │
└──────────────────────────┘
The primary mechanism of this executor is the special linked list/stack. This list has the following properties:
• Multiple node types:
◦ Task nodes (TaskNode), which have the following properties:
▪ Strongly connected (no task is ever removed from the middle of the list; tail can always be found by following .next pointers)
▪ FIFO (insertion at tail.next, "removal" at head.next)
▪ Head and tail always refer to TaskNodes; head.next/tail.next are the "true" action points for all node types
▪ At least one dead task node is always in the list, thus the task is cleared after execution to avoid leaks
◦ Waiting consumer thread nodes (PoolThreadNode), which have the following properties:
▪ LIFO/FILO (insertion and removal at tail.next)
▪ Carrier for task handoff between producer and waiting consumer
◦ Waiting termination (awaitTermination) thread nodes (TerminateWaiterNode), which have the following properties:
▪ Append-only (insertion at tail.next.next...next)
▪ All removed at once when termination is complete
▪ If a thread stops waiting, the node remains (but its thread field is cleared to prevent (best-effort) useless unparks)
▪ Once cleared, the thread field can never be reinitialized
• Concurrently accessed (multiple threads may read the list and update the head and tail pointers)
• TaskNode.next may be any node type or null
• PoolThreadNode.next may only be another PoolThreadNode or null
• TerminateWaiterNode.next may only be another TerminateWaiterNode or null
The secondary mechanism is the thread status atomic variable. It is logically a structure with the following fields:
• Current thread count (currentSizeOf(), withCurrentSize())
• Core pool size (coreSizeOf(), withCoreSize())
• Max pool size (maxSizeOf(), withMaxSize())
• Shutdown-requested flag (isShutdownRequested(), withShutdownRequested())
• Shutdown-with-interrupt requested flag (isShutdownInterrupt(), withShutdownInterrupt())
• Shutdown-completed flag (isShutdownComplete(), withShutdownComplete())
• The decision to create a new thread is affected by whether the number of active threads is less than the core size;
if not, then the growth resistance factor is applied to decide whether the task should be enqueued or a new thread begun.
Note: the default growth resistance factor is 0% resistance.
The final mechanism is the queue status atomic variable. It is logically a structure with the following fields:
• Current queue size (currentQueueSizeOf(), withCurrentQueueSize())
• Queue size limit (maxQueueSizeOf(), withMaxQueueSize())
*/
// =======================================================
// Optimization control flags
// =======================================================
/**
* A global hint which establishes whether it is recommended to disable uses of {@code EnhancedQueueExecutor}.
* This hint defaults to {@code false} but can be changed to {@code true} by setting the {@code jboss.threads.eqe.disable}
* property to {@code true} before this class is initialized.
*/
public static final boolean DISABLE_HINT = readBooleanPropertyPrefixed("disable", false);
/**
* Update the tail pointer opportunistically.
*/
static final boolean UPDATE_TAIL = readBooleanPropertyPrefixed("update-tail", false);
/**
* Update the summary statistics.
*/
static final boolean UPDATE_STATISTICS = readBooleanPropertyPrefixed("statistics", true);
/**
* Suppress queue limit and size tracking for performance.
*/
static final boolean NO_QUEUE_LIMIT = readBooleanPropertyPrefixed("unlimited-queue", false);
/**
* Set the default value for whether an mbean is to be auto-registered for the thread pool.
*/
static final boolean REGISTER_MBEAN = readBooleanPropertyPrefixed("register-mbean", true);
/**
* Set to enable or disable MBean registration.
*/
static final boolean DISABLE_MBEAN = readBooleanPropertyPrefixed("register-mbean", readProperty("org.graalvm.nativeimage.imagecode", null) != null);
// =======================================================
// Constants
// =======================================================
static final Executor DEFAULT_HANDLER = JBossExecutors.rejectingExecutor();
// =======================================================
// Immutable configuration fields
// =======================================================
/**
* The thread factory.
*/
private final ThreadFactory threadFactory;
/**
* The approximate set of pooled threads.
*/
private final Set runningThreads = Collections.newSetFromMap(new ConcurrentHashMap<>());
/**
* The management bean instance.
*/
private final MXBeanImpl mxBean;
/**
* The MBean registration handle (if any).
*/
private final Object handle;
/**
* The access control context of the creating thread.
*/
private final AccessControlContext acc;
// =======================================================
// Locks
// =======================================================
/**
* The tail lock. Only used if {@link #TAIL_LOCK} is {@code true}.
*/
private final ExtendedLock tailLock = TAIL_LOCK ? TAIL_SPIN ? new SpinLock() : Locks.reentrantLock() : null;
/**
* The head lock. Only used if {@link #HEAD_LOCK} is {@code true}.
*/
private final ExtendedLock headLock = COMBINED_LOCK ? tailLock : HEAD_LOCK ? HEAD_SPIN ? new SpinLock() : Locks.reentrantLock() : null;
// =======================================================
// Current state fields
// =======================================================
/**
* The linked list of threads waiting for termination of this thread pool.
*/
@SuppressWarnings("unused") // used by field updater
volatile Waiter terminationWaiters;
/**
* Queue size:
*
* - Bit 00..1F: current queue length
* - Bit 20..3F: queue limit
*
*/
@SuppressWarnings("unused") // used by field updater
volatile long queueSize;
/**
* The thread keep-alive timeout value.
*/
volatile long timeoutNanos;
/**
* A resistance factor applied after the core pool is full; values applied here will cause that fraction
* of submissions to create new threads when no idle thread is available. A value of {@code 0.0f} implies that
* threads beyond the core size should be created as aggressively as threads within it; a value of {@code 1.0f}
* implies that threads beyond the core size should never be created.
*/
volatile float growthResistance;
/**
* The handler for tasks which cannot be accepted by the executor.
*/
volatile Executor handoffExecutor;
/**
* The handler for uncaught exceptions which occur during user tasks.
*/
volatile Thread.UncaughtExceptionHandler exceptionHandler;
/**
* The termination task to execute when the thread pool exits.
*/
volatile Runnable terminationTask;
// =======================================================
// Statistics fields and counters
// =======================================================
/**
* The peak number of threads ever created by this pool.
*/
@SuppressWarnings("unused") // used by field updater
volatile int peakThreadCount;
/**
* The approximate peak queue size.
*/
@SuppressWarnings("unused") // used by field updater
volatile int peakQueueSize;
private final LongAdder submittedTaskCounter = new LongAdder();
private final LongAdder completedTaskCounter = new LongAdder();
private final LongAdder rejectedTaskCounter = new LongAdder();
private final LongAdder spinMisses = new LongAdder();
/**
* The current active number of threads.
*/
@SuppressWarnings("unused")
volatile int activeCount;
// =======================================================
// Updaters
// =======================================================
private static final long terminationWaitersOffset;
private static final long queueSizeOffset;
private static final long peakThreadCountOffset;
private static final long activeCountOffset;
private static final long peakQueueSizeOffset;
private static final Object sequenceBase;
private static final long sequenceOffset;
static {
try {
terminationWaitersOffset = unsafe.objectFieldOffset(EnhancedQueueExecutor.class.getDeclaredField("terminationWaiters"));
queueSizeOffset = unsafe.objectFieldOffset(EnhancedQueueExecutor.class.getDeclaredField("queueSize"));
peakThreadCountOffset = unsafe.objectFieldOffset(EnhancedQueueExecutor.class.getDeclaredField("peakThreadCount"));
activeCountOffset = unsafe.objectFieldOffset(EnhancedQueueExecutor.class.getDeclaredField("activeCount"));
peakQueueSizeOffset = unsafe.objectFieldOffset(EnhancedQueueExecutor.class.getDeclaredField("peakQueueSize"));
sequenceBase = unsafe.staticFieldBase(EnhancedQueueExecutor.class.getDeclaredField("sequence"));
sequenceOffset = unsafe.staticFieldOffset(EnhancedQueueExecutor.class.getDeclaredField("sequence"));
} catch (NoSuchFieldException e) {
throw new NoSuchFieldError(e.getMessage());
}
}
// =======================================================
// Thread state field constants
// =======================================================
private static final long TS_THREAD_CNT_MASK = 0b1111_1111_1111_1111_1111L; // 20 bits, can be shifted as needed
// shift amounts
private static final long TS_CURRENT_SHIFT = 0;
private static final long TS_CORE_SHIFT = 20;
private static final long TS_MAX_SHIFT = 40;
private static final long TS_ALLOW_CORE_TIMEOUT = 1L << 60;
private static final long TS_SHUTDOWN_REQUESTED = 1L << 61;
private static final long TS_SHUTDOWN_INTERRUPT = 1L << 62;
@SuppressWarnings("NumericOverflow")
private static final long TS_SHUTDOWN_COMPLETE = 1L << 63;
private static final int EXE_OK = 0;
private static final int EXE_REJECT_QUEUE_FULL = 1;
private static final int EXE_REJECT_SHUTDOWN = 2;
private static final int EXE_CREATE_THREAD = 3;
private static final int AT_YES = 0;
private static final int AT_NO = 1;
private static final int AT_SHUTDOWN = 2;
// =======================================================
// Marker objects
// =======================================================
static final QNode TERMINATE_REQUESTED = new TerminateWaiterNode();
static final QNode TERMINATE_COMPLETE = new TerminateWaiterNode();
static final Waiter TERMINATE_COMPLETE_WAITER = new Waiter(null);
static final Runnable WAITING = new NullRunnable();
static final Runnable GAVE_UP = new NullRunnable();
static final Runnable ACCEPTED = new NullRunnable();
static final Runnable EXIT = new NullRunnable();
// =======================================================
// Constructor
// =======================================================
static volatile int sequence = 1;
EnhancedQueueExecutor(final Builder builder) {
super();
this.acc = getContext();
int maxSize = builder.getMaximumPoolSize();
int coreSize = min(builder.getCorePoolSize(), maxSize);
this.handoffExecutor = builder.getHandoffExecutor();
this.exceptionHandler = builder.getExceptionHandler();
this.threadFactory = builder.getThreadFactory();
this.terminationTask = builder.getTerminationTask();
this.growthResistance = builder.getGrowthResistance();
final Duration keepAliveTime = builder.getKeepAliveTime();
// initial dead node
// thread stat
threadStatus = withCoreSize(withMaxSize(withAllowCoreTimeout(0L, builder.allowsCoreThreadTimeOut()), maxSize), coreSize);
timeoutNanos = TimeUtil.clampedPositiveNanos(keepAliveTime);
queueSize = withMaxQueueSize(withCurrentQueueSize(0L, 0), builder.getMaximumQueueSize());
mxBean = new MXBeanImpl();
if (! DISABLE_MBEAN && builder.isRegisterMBean()) {
final String configuredName = builder.getMBeanName();
final String finalName = configuredName != null ? configuredName : "threadpool-" + unsafe.getAndAddInt(sequenceBase, sequenceOffset, 1);
handle = doPrivileged(new MBeanRegisterAction(finalName, mxBean), acc);
} else {
handle = null;
}
}
static final class MBeanRegisterAction implements PrivilegedAction {
private final String finalName;
private final MXBeanImpl mxBean;
MBeanRegisterAction(final String finalName, final MXBeanImpl mxBean) {
this.finalName = finalName;
this.mxBean = mxBean;
}
public ObjectInstance run() {
try {
final Hashtable table = new Hashtable<>();
table.put("name", ObjectName.quote(finalName));
table.put("type", "thread-pool");
return ManagementFactory.getPlatformMBeanServer().registerMBean(mxBean, new ObjectName("jboss.threads", table));
} catch (Throwable ignored) {
}
return null;
}
}
// =======================================================
// Builder
// =======================================================
/**
* The builder class for an {@code EnhancedQueueExecutor}. All the fields are initialized to sensible defaults for
* a small thread pool.
*/
public static final class Builder {
private ThreadFactory threadFactory = Executors.defaultThreadFactory();
private Runnable terminationTask = NullRunnable.getInstance();
private Executor handoffExecutor = DEFAULT_HANDLER;
private Thread.UncaughtExceptionHandler exceptionHandler = JBossExecutors.loggingExceptionHandler();
private int coreSize = 16;
private int maxSize = 64;
private Duration keepAliveTime = Duration.ofSeconds(30);
private float growthResistance;
private boolean allowCoreTimeOut;
private int maxQueueSize = Integer.MAX_VALUE;
private boolean registerMBean = REGISTER_MBEAN;
private String mBeanName;
/**
* Construct a new instance.
*/
public Builder() {}
/**
* Get the configured thread factory.
*
* @return the configured thread factory (not {@code null})
*/
public ThreadFactory getThreadFactory() {
return threadFactory;
}
/**
* Set the configured thread factory.
*
* @param threadFactory the configured thread factory (must not be {@code null})
* @return this builder
*/
public Builder setThreadFactory(final ThreadFactory threadFactory) {
Assert.checkNotNullParam("threadFactory", threadFactory);
this.threadFactory = threadFactory;
return this;
}
/**
* Get the termination task. By default, an empty {@code Runnable} is used.
*
* @return the termination task (not {@code null})
*/
public Runnable getTerminationTask() {
return terminationTask;
}
/**
* Set the termination task.
*
* @param terminationTask the termination task (must not be {@code null})
* @return this builder
*/
public Builder setTerminationTask(final Runnable terminationTask) {
Assert.checkNotNullParam("terminationTask", terminationTask);
this.terminationTask = terminationTask;
return this;
}
/**
* Get the core pool size. This is the size below which new threads will always be created if no idle threads
* are available. If the pool size reaches the core size but has not yet reached the maximum size, a resistance
* factor will be applied to each task submission which determines whether the task should be queued or a new
* thread started.
*
* @return the core pool size
* @see EnhancedQueueExecutor#getCorePoolSize()
*/
public int getCorePoolSize() {
return coreSize;
}
/**
* Set the core pool size. If the configured maximum pool size is less than the configured core size, the
* core size will be reduced to match the maximum size when the thread pool is constructed.
*
* @param coreSize the core pool size (must be greater than or equal to 0, and less than 2^20)
* @return this builder
* @see EnhancedQueueExecutor#setCorePoolSize(int)
*/
public Builder setCorePoolSize(final int coreSize) {
Assert.checkMinimumParameter("coreSize", 0, coreSize);
Assert.checkMaximumParameter("coreSize", TS_THREAD_CNT_MASK, coreSize);
this.coreSize = coreSize;
return this;
}
/**
* Get the maximum pool size. This is the absolute upper limit to the size of the thread pool.
*
* @return the maximum pool size
* @see EnhancedQueueExecutor#getMaximumPoolSize()
*/
public int getMaximumPoolSize() {
return maxSize;
}
/**
* Set the maximum pool size. If the configured maximum pool size is less than the configured core size, the
* core size will be reduced to match the maximum size when the thread pool is constructed.
*
* @param maxSize the maximum pool size (must be greater than or equal to 0, and less than 2^20)
* @return this builder
* @see EnhancedQueueExecutor#setMaximumPoolSize(int)
*/
public Builder setMaximumPoolSize(final int maxSize) {
Assert.checkMinimumParameter("maxSize", 0, maxSize);
Assert.checkMaximumParameter("maxSize", TS_THREAD_CNT_MASK, maxSize);
this.maxSize = maxSize;
return this;
}
/**
* Get the thread keep-alive time. This is the amount of time (in the configured time unit) that idle threads
* will wait for a task before exiting.
*
* @return the thread keep-alive time duration
*/
public Duration getKeepAliveTime() {
return keepAliveTime;
}
/**
* Get the thread keep-alive time. This is the amount of time (in the configured time unit) that idle threads
* will wait for a task before exiting.
*
* @param keepAliveUnits the time keepAliveUnits of the keep-alive time (must not be {@code null})
* @return the thread keep-alive time
* @see EnhancedQueueExecutor#getKeepAliveTime(TimeUnit)
* @deprecated Use {@link #getKeepAliveTime()} instead.
*/
@Deprecated
public long getKeepAliveTime(TimeUnit keepAliveUnits) {
Assert.checkNotNullParam("keepAliveUnits", keepAliveUnits);
final long secondsPart = keepAliveUnits.convert(keepAliveTime.getSeconds(), TimeUnit.SECONDS);
final long nanoPart = keepAliveUnits.convert(keepAliveTime.getNano(), TimeUnit.NANOSECONDS);
final long sum = secondsPart + nanoPart;
return sum < 0 ? Long.MAX_VALUE : sum;
}
/**
* Set the thread keep-alive time.
*
* @param keepAliveTime the thread keep-alive time (must not be {@code null})
*/
public Builder setKeepAliveTime(final Duration keepAliveTime) {
Assert.checkNotNullParam("keepAliveTime", keepAliveTime);
this.keepAliveTime = keepAliveTime;
return this;
}
/**
* Set the thread keep-alive time.
*
* @param keepAliveTime the thread keep-alive time (must be greater than 0)
* @param keepAliveUnits the time keepAliveUnits of the keep-alive time (must not be {@code null})
* @return this builder
* @see EnhancedQueueExecutor#setKeepAliveTime(long, TimeUnit)
* @deprecated Use {@link #setKeepAliveTime(Duration)} instead.
*/
@Deprecated
public Builder setKeepAliveTime(final long keepAliveTime, final TimeUnit keepAliveUnits) {
Assert.checkMinimumParameter("keepAliveTime", 1L, keepAliveTime);
Assert.checkNotNullParam("keepAliveUnits", keepAliveUnits);
this.keepAliveTime = Duration.of(keepAliveTime, JDKSpecific.timeToTemporal(keepAliveUnits));
return this;
}
/**
* Get the thread pool growth resistance. This is the average fraction of submitted tasks that will be enqueued (instead
* of causing a new thread to start) when there are no idle threads and the pool size is equal to or greater than
* the core size (but still less than the maximum size). A value of {@code 0.0} indicates that tasks should
* not be enqueued until the pool is completely full; a value of {@code 1.0} indicates that tasks should always
* be enqueued until the queue is completely full.
*
* @return the thread pool growth resistance
* @see EnhancedQueueExecutor#getGrowthResistance()
*/
public float getGrowthResistance() {
return growthResistance;
}
/**
* Set the thread pool growth resistance.
*
* @param growthResistance the thread pool growth resistance (must be in the range {@code 0.0f ≤ n ≤ 1.0f})
* @return this builder
* @see #getGrowthResistance()
* @see EnhancedQueueExecutor#setGrowthResistance(float)
*/
public Builder setGrowthResistance(final float growthResistance) {
Assert.checkMinimumParameter("growthResistance", 0.0f, growthResistance);
Assert.checkMaximumParameter("growthResistance", 1.0f, growthResistance);
this.growthResistance = growthResistance;
return this;
}
/**
* Determine whether core threads are allowed to time out. A "core thread" is defined as any thread in the pool
* when the pool size is below the pool's {@linkplain #getCorePoolSize() core pool size}.
*
* @return {@code true} if core threads are allowed to time out, {@code false} otherwise
* @see EnhancedQueueExecutor#allowsCoreThreadTimeOut()
*/
public boolean allowsCoreThreadTimeOut() {
return allowCoreTimeOut;
}
/**
* Establish whether core threads are allowed to time out. A "core thread" is defined as any thread in the pool
* when the pool size is below the pool's {@linkplain #getCorePoolSize() core pool size}.
*
* @param allowCoreTimeOut {@code true} if core threads are allowed to time out, {@code false} otherwise
* @return this builder
* @see EnhancedQueueExecutor#allowCoreThreadTimeOut(boolean)
*/
public Builder allowCoreThreadTimeOut(final boolean allowCoreTimeOut) {
this.allowCoreTimeOut = allowCoreTimeOut;
return this;
}
/**
* Get the maximum queue size. If the queue is full and a task cannot be immediately accepted, rejection will result.
*
* @return the maximum queue size
* @see EnhancedQueueExecutor#getMaximumQueueSize()
*/
public int getMaximumQueueSize() {
return maxQueueSize;
}
/**
* Set the maximum queue size.
*
* @param maxQueueSize the maximum queue size (must be ≥ 0)
* @return this builder
* @see EnhancedQueueExecutor#setMaximumQueueSize(int)
*/
public Builder setMaximumQueueSize(final int maxQueueSize) {
Assert.checkMinimumParameter("maxQueueSize", 0, maxQueueSize);
Assert.checkMaximumParameter("maxQueueSize", Integer.MAX_VALUE, maxQueueSize);
this.maxQueueSize = maxQueueSize;
return this;
}
/**
* Get the handoff executor.
*
* @return the handoff executor (not {@code null})
*/
public Executor getHandoffExecutor() {
return handoffExecutor;
}
/**
* Set the handoff executor.
*
* @param handoffExecutor the handoff executor (must not be {@code null})
* @return this builder
*/
public Builder setHandoffExecutor(final Executor handoffExecutor) {
Assert.checkNotNullParam("handoffExecutor", handoffExecutor);
this.handoffExecutor = handoffExecutor;
return this;
}
/**
* Get the uncaught exception handler.
*
* @return the uncaught exception handler (not {@code null})
*/
public Thread.UncaughtExceptionHandler getExceptionHandler() {
return exceptionHandler;
}
/**
* Set the uncaught exception handler.
*
* @param exceptionHandler the uncaught exception handler (must not be {@code null})
* @return this builder
*/
public Builder setExceptionHandler(final Thread.UncaughtExceptionHandler exceptionHandler) {
this.exceptionHandler = exceptionHandler;
return this;
}
/**
* Construct the executor from the configured parameters.
*
* @return the executor, which will be active and ready to accept tasks (not {@code null})
*/
public EnhancedQueueExecutor build() {
return new EnhancedQueueExecutor(this);
}
/**
* Determine whether an MBean should automatically be registered for this pool.
*
* @return {@code true} if an MBean is to be auto-registered; {@code false} otherwise
*/
public boolean isRegisterMBean() {
return registerMBean;
}
/**
* Establish whether an MBean should automatically be registered for this pool.
*
* @param registerMBean {@code true} if an MBean is to be auto-registered; {@code false} otherwise
* @return this builder
*/
public Builder setRegisterMBean(final boolean registerMBean) {
this.registerMBean = registerMBean;
return this;
}
/**
* Get the overridden MBean name.
*
* @return the overridden MBean name, or {@code null} if a default name should be generated
*/
public String getMBeanName() {
return mBeanName;
}
/**
* Set the overridden MBean name.
*
* @param mBeanName the overridden MBean name, or {@code null} if a default name should be generated
* @return this builder
*/
public Builder setMBeanName(final String mBeanName) {
this.mBeanName = mBeanName;
return this;
}
}
// =======================================================
// ExecutorService
// =======================================================
/**
* Execute a task.
*
* @param runnable the task to execute (must not be {@code null})
*/
public void execute(Runnable runnable) {
Assert.checkNotNullParam("runnable", runnable);
final Runnable realRunnable = JBossExecutors.classLoaderPreservingTaskUnchecked(runnable);
int result;
if (TAIL_LOCK) {
Lock lock = this.tailLock;
lock.lock();
try {
result = tryExecute(realRunnable);
} finally {
lock.unlock();
}
} else {
result = tryExecute(realRunnable);
}
boolean ok = false;
if (result == EXE_OK) {
// last check to ensure that there is at least one existent thread to avoid rare thread timeout race condition
if (currentSizeOf(threadStatus) == 0 && tryAllocateThread(0.0f) == AT_YES && ! doStartThread(null)) {
deallocateThread();
}
if (UPDATE_STATISTICS) submittedTaskCounter.increment();
return;
} else if (result == EXE_CREATE_THREAD) try {
ok = doStartThread(realRunnable);
} finally {
if (! ok) deallocateThread();
} else {
if (UPDATE_STATISTICS) rejectedTaskCounter.increment();
if (result == EXE_REJECT_SHUTDOWN) {
rejectShutdown(realRunnable);
} else {
assert result == EXE_REJECT_QUEUE_FULL;
rejectQueueFull(realRunnable);
}
}
}
/**
* Request that shutdown be initiated for this thread pool. This is equivalent to calling
* {@link #shutdown(boolean) shutdown(false)}; see that method for more information.
*/
public void shutdown() {
shutdown(false);
}
/**
* Attempt to stop the thread pool immediately by interrupting all running threads and de-queueing all pending
* tasks. The thread pool might not be fully stopped when this method returns, if a currently running task
* does not respect interruption.
*
* @return a list of pending tasks (not {@code null})
*/
public List shutdownNow() {
shutdown(true);
final ArrayList list = new ArrayList<>();
TaskNode head = this.head;
QNode headNext;
for (;;) {
headNext = head.getNext();
if (headNext instanceof TaskNode) {
TaskNode taskNode = (TaskNode) headNext;
if (compareAndSetHead(head, taskNode)) {
if (! NO_QUEUE_LIMIT) decreaseQueueSize();
head = taskNode;
list.add(taskNode.task);
}
// retry
} else {
// no more tasks;
return list;
}
}
}
/**
* Determine whether shutdown was requested on this thread pool.
*
* @return {@code true} if shutdown was requested, {@code false} otherwise
*/
public boolean isShutdown() {
return isShutdownRequested(threadStatus);
}
/**
* Determine whether shutdown has completed on this thread pool.
*
* @return {@code true} if shutdown has completed, {@code false} otherwise
*/
public boolean isTerminated() {
return isShutdownComplete(threadStatus);
}
/**
* Wait for the thread pool to complete termination. If the timeout expires before the thread pool is terminated,
* {@code false} is returned. If the calling thread is interrupted before the thread pool is terminated, then
* an {@link InterruptedException} is thrown.
*
* @param timeout the amount of time to wait (must be ≥ 0)
* @param unit the unit of time to use for waiting (must not be {@code null})
* @return {@code true} if the thread pool terminated within the given timeout, {@code false} otherwise
* @throws InterruptedException if the calling thread was interrupted before either the time period elapsed or the pool terminated successfully
*/
public boolean awaitTermination(final long timeout, final TimeUnit unit) throws InterruptedException {
Assert.checkMinimumParameter("timeout", 0, timeout);
Assert.checkNotNullParam("unit", unit);
if (timeout > 0) {
final Thread thread = Thread.currentThread();
if (runningThreads.contains(thread)) {
throw Messages.msg.cannotAwaitWithin();
}
Waiter waiters = this.terminationWaiters;
if (waiters == TERMINATE_COMPLETE_WAITER) {
return true;
}
final Waiter waiter = new Waiter(waiters);
waiter.setThread(currentThread());
while (! compareAndSetTerminationWaiters(waiters, waiter)) {
waiters = this.terminationWaiters;
if (waiters == TERMINATE_COMPLETE_WAITER) {
return true;
}
waiter.setNext(waiters);
}
try {
parkNanos(this, unit.toNanos(timeout));
} finally {
// prevent future spurious unparks without sabotaging the queue's integrity
waiter.setThread(null);
}
}
if (Thread.interrupted()) throw new InterruptedException();
return isTerminated();
}
// =======================================================
// Management
// =======================================================
public StandardThreadPoolMXBean getThreadPoolMXBean() {
return mxBean;
}
// =======================================================
// Other public API
// =======================================================
/**
* Initiate shutdown of this thread pool. After this method is called, no new tasks will be accepted. Once
* the last task is complete, the thread pool will be terminated and its
* {@linkplain Builder#setTerminationTask(Runnable) termination task}
* will be called. Calling this method more than once has no additional effect, unless all previous calls
* had the {@code interrupt} parameter set to {@code false} and the subsequent call sets it to {@code true}, in
* which case all threads in the pool will be interrupted.
*
* @param interrupt {@code true} to request that currently-running tasks be interrupted; {@code false} otherwise
*/
public void shutdown(boolean interrupt) {
long oldStatus, newStatus;
// state change sh1:
// threadStatus ← threadStatus | shutdown
// succeeds: -
// preconditions:
// none (thread status may be in any state)
// postconditions (succeed):
// (always) ShutdownRequested set in threadStatus
// (maybe) ShutdownInterrupted set in threadStatus (depends on parameter)
// (maybe) ShutdownComplete set in threadStatus (if currentSizeOf() == 0)
// (maybe) exit if no change
// postconditions (fail): -
// post-actions (fail):
// repeat state change until success or return
do {
oldStatus = threadStatus;
newStatus = withShutdownRequested(oldStatus);
if (interrupt) newStatus = withShutdownInterrupt(newStatus);
if (currentSizeOf(oldStatus) == 0) newStatus = withShutdownComplete(newStatus);
if (newStatus == oldStatus) return;
} while (! compareAndSetThreadStatus(oldStatus, newStatus));
assert oldStatus != newStatus;
if (isShutdownRequested(newStatus) != isShutdownRequested(oldStatus)) {
assert ! isShutdownRequested(oldStatus); // because it can only ever be set, not cleared
// we initiated shutdown
// clear out all consumers and append a dummy waiter node
TaskNode tail = this.tail;
QNode tailNext;
// a marker to indicate that termination was requested
for (;;) {
tailNext = tail.getNext();
if (tailNext instanceof TaskNode) {
tail = (TaskNode) tailNext;
} else if (tailNext instanceof PoolThreadNode || tailNext == null) {
// remove the entire chain from this point
PoolThreadNode node = (PoolThreadNode) tailNext;
// state change sh2:
// tail.next ← terminateNode(null)
// succeeds: sh1
// preconditions:
// threadStatus contains shutdown
// tail(snapshot) is a task node
// tail(snapshot).next is a (list of) pool thread node(s) or null
// postconditions (succeed):
// tail(snapshot).next is TERMINATE_REQUESTED
if (tail.compareAndSetNext(node, TERMINATE_REQUESTED)) {
// got it!
// state change sh3:
// node.task ← EXIT
// preconditions:
// none (node task may be in any state)
// postconditions (succeed):
// task is EXIT
// postconditions (fail):
// no change (repeat loop)
while (node != null) {
node.compareAndSetTask(WAITING, EXIT);
unpark(node.thread);
node = node.getNext();
}
// success; exit loop
break;
}
// repeat loop (failed CAS)
} else if (tailNext instanceof TerminateWaiterNode) {
// theoretically impossible, but it means we have nothing else to do
break;
} else {
throw Assert.unreachableCode();
}
}
}
if (isShutdownInterrupt(newStatus) != isShutdownInterrupt(oldStatus)) {
assert ! isShutdownInterrupt(oldStatus); // because it can only ever be set, not cleared
// we initiated interrupt, so interrupt all currently active threads
for (Thread thread : runningThreads) {
thread.interrupt();
}
}
if (isShutdownComplete(newStatus) != isShutdownComplete(oldStatus)) {
assert ! isShutdownComplete(oldStatus); // because it can only ever be set, not cleared
completeTermination();
}
}
/**
* Determine if this thread pool is in the process of terminating but has not yet completed.
*
* @return {@code true} if the thread pool is terminating, or {@code false} if the thread pool is not terminating or has completed termination
*/
public boolean isTerminating() {
final long threadStatus = this.threadStatus;
return isShutdownRequested(threadStatus) && ! isShutdownComplete(threadStatus);
}
/**
* Start an idle core thread. Normally core threads are only begun when a task was submitted to the executor
* but no thread is immediately available to handle the task.
*
* @return {@code true} if a core thread was started, or {@code false} if all core threads were already running or
* if the thread failed to be created for some other reason
*/
public boolean prestartCoreThread() {
if (tryAllocateThread(1.0f) != AT_YES) return false;
if (doStartThread(null)) return true;
deallocateThread();
return false;
}
/**
* Start all core threads. Calls {@link #prestartCoreThread()} in a loop until it returns {@code false}.
*
* @return the number of core threads created
*/
public int prestartAllCoreThreads() {
int cnt = 0;
while (prestartCoreThread()) cnt ++;
return cnt;
}
// =======================================================
// Tuning & configuration parameters (run time)
// =======================================================
/**
* Get the thread pool growth resistance. This is the average fraction of submitted tasks that will be enqueued (instead
* of causing a new thread to start) when there are no idle threads and the pool size is equal to or greater than
* the core size (but still less than the maximum size). A value of {@code 0.0} indicates that tasks should
* not be enqueued until the pool is completely full; a value of {@code 1.0} indicates that tasks should always
* be enqueued until the queue is completely full.
*
* @return the configured growth resistance factor
* @see Builder#getGrowthResistance() Builder.getGrowthResistance()
*/
public float getGrowthResistance() {
return growthResistance;
}
/**
* Set the growth resistance factor.
*
* @param growthResistance the thread pool growth resistance (must be in the range {@code 0.0f ≤ n ≤ 1.0f})
* @see Builder#setGrowthResistance(float) Builder.setGrowthResistance()
*/
public void setGrowthResistance(final float growthResistance) {
Assert.checkMinimumParameter("growthResistance", 0.0f, growthResistance);
Assert.checkMaximumParameter("growthResistance", 1.0f, growthResistance);
this.growthResistance = growthResistance;
}
/**
* Get the core pool size. This is the size below which new threads will always be created if no idle threads
* are available. If the pool size reaches the core size but has not yet reached the maximum size, a resistance
* factor will be applied to each task submission which determines whether the task should be queued or a new
* thread started.
*
* @return the core pool size
* @see Builder#getCorePoolSize() Builder.getCorePoolSize()
*/
public int getCorePoolSize() {
return coreSizeOf(threadStatus);
}
/**
* Set the core pool size. If the configured maximum pool size is less than the configured core size, the
* core size will be reduced to match the maximum size when the thread pool is constructed.
*
* @param corePoolSize the core pool size (must be greater than or equal to 0, and less than 2^20)
* @see Builder#setCorePoolSize(int) Builder.setCorePoolSize()
*/
public void setCorePoolSize(final int corePoolSize) {
Assert.checkMinimumParameter("corePoolSize", 0, corePoolSize);
Assert.checkMaximumParameter("corePoolSize", TS_THREAD_CNT_MASK, corePoolSize);
long oldVal, newVal;
do {
oldVal = threadStatus;
if (corePoolSize > maxSizeOf(oldVal)) {
// automatically bump up max size to match
newVal = withCoreSize(withMaxSize(oldVal, corePoolSize), corePoolSize);
} else {
newVal = withCoreSize(oldVal, corePoolSize);
}
} while (! compareAndSetThreadStatus(oldVal, newVal));
if (maxSizeOf(newVal) < maxSizeOf(oldVal) || coreSizeOf(newVal) < coreSizeOf(oldVal)) {
// poke all the threads to try to terminate any excess eagerly
for (Thread activeThread : runningThreads) {
unpark(activeThread);
}
}
}
/**
* Get the maximum pool size. This is the absolute upper limit to the size of the thread pool.
*
* @return the maximum pool size
* @see Builder#getMaximumPoolSize() Builder.getMaximumPoolSize()
*/
public int getMaximumPoolSize() {
return maxSizeOf(threadStatus);
}
/**
* Set the maximum pool size. If the configured maximum pool size is less than the configured core size, the
* core size will be reduced to match the maximum size when the thread pool is constructed.
*
* @param maxPoolSize the maximum pool size (must be greater than or equal to 0, and less than 2^20)
* @see Builder#setMaximumPoolSize(int) Builder.setMaximumPoolSize()
*/
public void setMaximumPoolSize(final int maxPoolSize) {
Assert.checkMinimumParameter("maxPoolSize", 0, maxPoolSize);
Assert.checkMaximumParameter("maxPoolSize", TS_THREAD_CNT_MASK, maxPoolSize);
long oldVal, newVal;
do {
oldVal = threadStatus;
if (maxPoolSize < coreSizeOf(oldVal)) {
// automatically bump down core size to match
newVal = withCoreSize(withMaxSize(oldVal, maxPoolSize), maxPoolSize);
} else {
newVal = withMaxSize(oldVal, maxPoolSize);
}
} while (! compareAndSetThreadStatus(oldVal, newVal));
if (maxSizeOf(newVal) < maxSizeOf(oldVal) || coreSizeOf(newVal) < coreSizeOf(oldVal)) {
// poke all the threads to try to terminate any excess eagerly
for (Thread activeThread : runningThreads) {
unpark(activeThread);
}
}
}
/**
* Determine whether core threads are allowed to time out. A "core thread" is defined as any thread in the pool
* when the pool size is below the pool's {@linkplain #getCorePoolSize() core pool size}.
*
* @return {@code true} if core threads are allowed to time out, {@code false} otherwise
* @see Builder#allowsCoreThreadTimeOut() Builder.allowsCoreThreadTimeOut()
*/
public boolean allowsCoreThreadTimeOut() {
return isAllowCoreTimeout(threadStatus);
}
/**
* Establish whether core threads are allowed to time out. A "core thread" is defined as any thread in the pool
* when the pool size is below the pool's {@linkplain #getCorePoolSize() core pool size}.
*
* @param value {@code true} if core threads are allowed to time out, {@code false} otherwise
* @see Builder#allowCoreThreadTimeOut(boolean) Builder.allowCoreThreadTimeOut()
*/
public void allowCoreThreadTimeOut(boolean value) {
long oldVal, newVal;
do {
oldVal = threadStatus;
newVal = withAllowCoreTimeout(oldVal, value);
if (oldVal == newVal) return;
} while (! compareAndSetThreadStatus(oldVal, newVal));
if (value) {
// poke all the threads to try to terminate any excess eagerly
for (Thread activeThread : runningThreads) {
unpark(activeThread);
}
}
}
/**
* Get the thread keep-alive time. This is the minimum length of time that idle threads should remain until they exit.
* Unless core threads are allowed to time out, threads will only exit if the current thread count exceeds the core
* limit.
*
* @param keepAliveUnits the unit in which the result should be expressed (must not be {@code null})
* @return the amount of time (will be greater than zero)
* @see Builder#getKeepAliveTime(TimeUnit) Builder.getKeepAliveTime()
* @deprecated Use {@link #getKeepAliveTime()} instead.
*/
@Deprecated
public long getKeepAliveTime(TimeUnit keepAliveUnits) {
Assert.checkNotNullParam("keepAliveUnits", keepAliveUnits);
return keepAliveUnits.convert(timeoutNanos, TimeUnit.NANOSECONDS);
}
/**
* Get the thread keep-alive time. This is the minimum length of time that idle threads should remain until they exit.
* Unless core threads are allowed to time out, threads will only exit if the current thread count exceeds the core
* limit.
*
* @return the amount of time (will be greater than zero)
* @see Builder#getKeepAliveTime() Builder.getKeepAliveTime()
*/
public Duration getKeepAliveTime() {
return Duration.of(timeoutNanos, ChronoUnit.NANOS);
}
/**
* Set the thread keep-alive time. This is the minimum length of time that idle threads should remain until they exit.
* Unless core threads are allowed to time out, threads will only exit if the current thread count exceeds the core
* limit.
*
* @param keepAliveTime the thread keep-alive time (must be > 0)
* @param keepAliveUnits the unit in which the value is expressed (must not be {@code null})
* @see Builder#setKeepAliveTime(long, TimeUnit) Builder.setKeepAliveTime()
* @deprecated Use {@link #setKeepAliveTime(Duration)} instead.
*/
@Deprecated
public void setKeepAliveTime(final long keepAliveTime, final TimeUnit keepAliveUnits) {
Assert.checkMinimumParameter("keepAliveTime", 1L, keepAliveTime);
Assert.checkNotNullParam("keepAliveUnits", keepAliveUnits);
timeoutNanos = max(1L, keepAliveUnits.toNanos(keepAliveTime));
}
/**
* Set the thread keep-alive time. This is the minimum length of time that idle threads should remain until they exit.
* Unless core threads are allowed to time out, threads will only exit if the current thread count exceeds the core
* limit.
*
* @param keepAliveTime the thread keep-alive time (must not be {@code null})
* @see Builder#setKeepAliveTime(Duration) Builder.setKeepAliveTime()
*/
public void setKeepAliveTime(final Duration keepAliveTime) {
Assert.checkNotNullParam("keepAliveTime", keepAliveTime);
timeoutNanos = TimeUtil.clampedPositiveNanos(keepAliveTime);
}
/**
* Get the maximum queue size. If the queue is full and a task cannot be immediately accepted, rejection will result.
*
* @return the maximum queue size
* @see Builder#getMaximumQueueSize() Builder.getMaximumQueueSize()
*/
public int getMaximumQueueSize() {
return maxQueueSizeOf(queueSize);
}
/**
* Set the maximum queue size. If the new maximum queue size is smaller than the current queue size, there is no
* effect other than preventing tasks from being enqueued until the size decreases below the maximum again.
*
* @param maxQueueSize the maximum queue size (must be ≥ 0)
* @see Builder#setMaximumQueueSize(int) Builder.setMaximumQueueSize()
*/
public void setMaximumQueueSize(final int maxQueueSize) {
Assert.checkMinimumParameter("maxQueueSize", 0, maxQueueSize);
Assert.checkMaximumParameter("maxQueueSize", Integer.MAX_VALUE, maxQueueSize);
if (NO_QUEUE_LIMIT) return;
long oldVal;
do {
oldVal = queueSize;
} while (! compareAndSetQueueSize(oldVal, withMaxQueueSize(oldVal, maxQueueSize)));
}
/**
* Get the executor to delegate to in the event of task rejection.
*
* @return the executor to delegate to in the event of task rejection (not {@code null})
*/
public Executor getHandoffExecutor() {
return handoffExecutor;
}
/**
* Set the executor to delegate to in the event of task rejection.
*
* @param handoffExecutor the executor to delegate to in the event of task rejection (must not be {@code null})
*/
public void setHandoffExecutor(final Executor handoffExecutor) {
Assert.checkNotNullParam("handoffExecutor", handoffExecutor);
this.handoffExecutor = handoffExecutor;
}
/**
* Get the exception handler to use for uncaught exceptions.
*
* @return the exception handler to use for uncaught exceptions (not {@code null})
*/
public Thread.UncaughtExceptionHandler getExceptionHandler() {
return exceptionHandler;
}
/**
* Set the exception handler to use for uncaught exceptions.
*
* @param exceptionHandler the exception handler to use for uncaught exceptions (must not be {@code null})
*/
public void setExceptionHandler(final Thread.UncaughtExceptionHandler exceptionHandler) {
Assert.checkNotNullParam("exceptionHandler", exceptionHandler);
this.exceptionHandler = exceptionHandler;
}
/**
* Set the termination task, overwriting any previous setting.
*
* @param terminationTask the termination task, or {@code null} to perform no termination task
*/
public void setTerminationTask(final Runnable terminationTask) {
this.terminationTask = terminationTask;
}
// =======================================================
// Statistics & metrics API
// =======================================================
/**
* Get an estimate of the current queue size.
*
* @return an estimate of the current queue size
*/
public int getQueueSize() {
return currentQueueSizeOf(queueSize);
}
/**
* Get an estimate of the peak number of threads that the pool has ever held.
*
* @return an estimate of the peak number of threads that the pool has ever held
*/
public int getLargestPoolSize() {
return peakThreadCount;
}
/**
* Get an estimate of the number of threads which are currently doing work on behalf of the thread pool.
*
* @return the active count estimate
*/
public int getActiveCount() {
return activeCount;
}
/**
* Get an estimate of the peak size of the queue.
*
* @return an estimate of the peak size of the queue
*/
public int getLargestQueueSize() {
return peakQueueSize;
}
/**
* Get an estimate of the total number of tasks ever submitted to this thread pool.
*
* @return an estimate of the total number of tasks ever submitted to this thread pool
*/
public long getSubmittedTaskCount() {
return submittedTaskCounter.longValue();
}
/**
* Get an estimate of the total number of tasks ever rejected by this thread pool for any reason.
*
* @return an estimate of the total number of tasks ever rejected by this thread pool
*/
public long getRejectedTaskCount() {
return rejectedTaskCounter.longValue();
}
/**
* Get an estimate of the number of tasks completed by this thread pool.
*
* @return an estimate of the number of tasks completed by this thread pool
*/
public long getCompletedTaskCount() {
return completedTaskCounter.longValue();
}
/**
* Get an estimate of the current number of active threads in the pool.
*
* @return an estimate of the current number of active threads in the pool
*/
public int getPoolSize() {
return currentSizeOf(threadStatus);
}
/**
* Get an array containing an approximate snapshot of the currently running threads in
* this executor.
*
* @return an array of running (unterminated) threads (not {@code null})
*/
public Thread[] getRunningThreads() {
return runningThreads.toArray(NO_THREADS);
}
// =======================================================
// Pooled thread body
// =======================================================
final class ThreadBody implements Runnable {
private Runnable initialTask;
ThreadBody(final Runnable initialTask) {
this.initialTask = initialTask;
}
/**
* Execute the body of the thread. On entry the thread is added to the {@link #runningThreads} set, and on
* exit it is removed.
*/
public void run() {
final Thread currentThread = Thread.currentThread();
final Lock headLock = EnhancedQueueExecutor.this.headLock;
final LongAdder spinMisses = EnhancedQueueExecutor.this.spinMisses;
runningThreads.add(currentThread);
// run the initial task
doRunTask(getAndClearInitialTask());
// main loop
QNode node;
processingQueue: for (;;) {
if (HEAD_LOCK) {
headLock.lock();
try {
node = getOrAddNode();
} finally {
headLock.unlock();
}
} else {
node = getOrAddNode();
}
if (node instanceof TaskNode) {
// task node was removed
doRunTask(((TaskNode) node).getAndClearTask());
continue;
} else if (node instanceof PoolThreadNode) {
// pool thread node was added
final PoolThreadNode newNode = (PoolThreadNode) node;
// at this point, we are registered into the queue
long start = System.nanoTime();
long elapsed = 0L;
waitingForTask: for (;;) {
Runnable task = newNode.getTask();
assert task != ACCEPTED && task != GAVE_UP;
if (task != WAITING && task != EXIT) {
if (newNode.compareAndSetTask(task, ACCEPTED)) {
// we have a task to run, so run it and then abandon the node
doRunTask(task);
// rerun outer
continue processingQueue;
}
// we had a task to run, but we failed to CAS it for some reason, so retry
if (UPDATE_STATISTICS) spinMisses.increment();
continue waitingForTask;
} else {
final long timeoutNanos = EnhancedQueueExecutor.this.timeoutNanos;
long oldVal = threadStatus;
if (elapsed >= timeoutNanos || task == EXIT || currentSizeOf(oldVal) > maxSizeOf(oldVal)) {
// try to exit this thread, if we are allowed
if (task == EXIT ||
isShutdownRequested(oldVal) ||
isAllowCoreTimeout(oldVal) ||
currentSizeOf(oldVal) > coreSizeOf(oldVal)
) {
if (newNode.compareAndSetTask(task, GAVE_UP)) {
for (;;) {
if (tryDeallocateThread(oldVal)) {
// clear to exit.
runningThreads.remove(currentThread);
return;
}
if (UPDATE_STATISTICS) spinMisses.increment();
oldVal = threadStatus;
}
//throw Assert.unreachableCode();
}
continue waitingForTask;
} else {
if (elapsed >= timeoutNanos) {
park(EnhancedQueueExecutor.this);
} else {
parkNanos(EnhancedQueueExecutor.this, timeoutNanos - elapsed);
}
Thread.interrupted();
elapsed = System.nanoTime() - start;
// retry inner
continue waitingForTask;
}
//throw Assert.unreachableCode();
} else {
assert task == WAITING;
parkNanos(EnhancedQueueExecutor.this, timeoutNanos - elapsed);
Thread.interrupted();
elapsed = System.nanoTime() - start;
// retry inner
continue waitingForTask;
}
//throw Assert.unreachableCode();
}
//throw Assert.unreachableCode();
} // :waitingForTask
//throw Assert.unreachableCode();
} else {
assert node instanceof TerminateWaiterNode;
// we're shutting down!
runningThreads.remove(currentThread);
deallocateThread();
return;
}
//throw Assert.unreachableCode();
} // :processingQueue
//throw Assert.unreachableCode();
}
private QNode getOrAddNode() {
TaskNode head;
QNode headNext;
for (;;) {
head = EnhancedQueueExecutor.this.head;
headNext = head.getNext();
if (headNext instanceof TaskNode) {
TaskNode taskNode = (TaskNode) headNext;
if (compareAndSetHead(head, taskNode)) {
if (! NO_QUEUE_LIMIT) decreaseQueueSize();
return taskNode;
}
} else if (headNext instanceof PoolThreadNode || headNext == null) {
PoolThreadNode newNode;
newNode = new PoolThreadNode((PoolThreadNode) headNext, Thread.currentThread());
if (head.compareAndSetNext(headNext, newNode)) {
return newNode;
}
} else {
assert headNext instanceof TerminateWaiterNode;
return headNext;
}
if (UPDATE_STATISTICS) spinMisses.increment();
}
}
private Runnable getAndClearInitialTask() {
try {
return initialTask;
} finally {
this.initialTask = null;
}
}
void doRunTask(final Runnable task) {
if (task != null) {
if (isShutdownInterrupt(threadStatus)) {
Thread.currentThread().interrupt();
} else {
Thread.interrupted();
}
if (UPDATE_STATISTICS) incrementActiveCount();
safeRun(task);
if (UPDATE_STATISTICS) {
decrementActiveCount();
completedTaskCounter.increment();
}
}
}
}
// =======================================================
// Thread starting
// =======================================================
/**
* Allocate a new thread.
*
* @param growthResistance the growth resistance to apply
* @return {@code AT_YES} if a thread is allocated; {@code AT_NO} if a thread was not allocated; {@code AT_SHUTDOWN} if the pool is being shut down
*/
int tryAllocateThread(final float growthResistance) {
int oldSize;
long oldStat;
for (;;) {
oldStat = threadStatus;
if (isShutdownRequested(oldStat)) {
return AT_SHUTDOWN;
}
oldSize = currentSizeOf(oldStat);
if (oldSize >= maxSizeOf(oldStat)) {
// max threads already reached
return AT_NO;
}
if (oldSize >= coreSizeOf(oldStat) && oldSize > 0) {
// core threads are reached; check resistance factor (if no threads are running, then always start a thread)
if (growthResistance != 0.0f && (growthResistance == 1.0f || ThreadLocalRandom.current().nextFloat() < growthResistance)) {
// do not create a thread this time
return AT_NO;
}
}
// try to increase
final int newSize = oldSize + 1;
// state change ex3:
// threadStatus.size ← threadStatus(snapshot).size + 1
// cannot succeed: sh1
// succeeds: -
// preconditions:
// ! threadStatus(snapshot).shutdownRequested
// threadStatus(snapshot).size < threadStatus(snapshot).maxSize
// threadStatus(snapshot).size < threadStatus(snapshot).coreSize || random < growthResistance
// post-actions (fail):
// retry whole loop
if (compareAndSetThreadStatus(oldStat, withCurrentSize(oldStat, newSize))) {
// increment peak thread count
if (UPDATE_STATISTICS) {
int oldVal;
do {
oldVal = peakThreadCount;
if (oldVal >= newSize) break;
} while (! compareAndSetPeakThreadCount(oldVal, newSize));
}
return AT_YES;
}
if (UPDATE_STATISTICS) spinMisses.increment();
}
}
/**
* Roll back a thread allocation, possibly terminating the pool. Only call after {@link #tryAllocateThread(float)} returns {@link #AT_YES}.
*/
void deallocateThread() {
long oldStat;
do {
oldStat = threadStatus;
} while (! tryDeallocateThread(oldStat));
}
/**
* Try to roll back a thread allocation, possibly running the termination task if the pool would be terminated
* by last thread exit.
*
* @param oldStat the {@code threadStatus} to CAS
* @return {@code true} if the thread was deallocated, or {@code false} to retry with a new {@code oldStat}
*/
boolean tryDeallocateThread(long oldStat) {
assert ! currentThreadHolds(headLock) && ! currentThreadHolds(tailLock);
// roll back our thread allocation attempt
// state change ex4:
// threadStatus.size ← threadStatus.size - 1
// succeeds: ex3
// preconditions:
// threadStatus.size > 0
long newStat = withCurrentSize(oldStat, currentSizeOf(oldStat) - 1);
if (currentSizeOf(newStat) == 0 && isShutdownRequested(oldStat)) {
newStat = withShutdownComplete(newStat);
}
if (! compareAndSetThreadStatus(oldStat, newStat)) return false;
if (isShutdownComplete(newStat)) {
completeTermination();
}
return true;
}
/**
* Start an allocated thread.
*
* @param runnable the task or {@code null}
* @return {@code true} if the thread was started, {@code false} otherwise
* @throws RejectedExecutionException if {@code runnable} is not {@code null} and the thread could not be created or started
*/
boolean doStartThread(Runnable runnable) throws RejectedExecutionException {
assert ! currentThreadHolds(headLock) && ! currentThreadHolds(tailLock);
Thread thread;
try {
thread = threadFactory.newThread(new ThreadBody(runnable));
} catch (Throwable t) {
if (runnable != null) {
if (UPDATE_STATISTICS) rejectedTaskCounter.increment();
rejectException(runnable, t);
}
return false;
}
if (thread == null) {
if (runnable != null) {
if (UPDATE_STATISTICS) rejectedTaskCounter.increment();
rejectNoThread(runnable);
}
return false;
}
try {
thread.start();
} catch (Throwable t) {
if (runnable != null) {
if (UPDATE_STATISTICS) rejectedTaskCounter.increment();
rejectException(runnable, t);
}
return false;
}
return true;
}
// =======================================================
// Task submission
// =======================================================
private int tryExecute(final Runnable runnable) {
QNode tailNext;
TaskNode tail = this.tail;
final int result;
for (;;) {
tailNext = tail.getNext();
if (tailNext instanceof TaskNode) {
TaskNode tailNextTaskNode;
do {
if (UPDATE_STATISTICS) spinMisses.increment();
tailNextTaskNode = (TaskNode) tailNext;
// retry
tail = tailNextTaskNode;
tailNext = tail.getNext();
} while (tailNext instanceof TaskNode);
// opportunistically update for the possible benefit of other threads
if (UPDATE_TAIL) compareAndSetTail(tail, tailNextTaskNode);
}
// we've progressed to the first non-task node, as far as we can see
assert ! (tailNext instanceof TaskNode);
if (tailNext instanceof PoolThreadNode) {
final QNode tailNextNext = tailNext.getNext();
// state change ex1:
// tail(snapshot).next ← tail(snapshot).next(snapshot).next(snapshot)
// succeeds: -
// cannot succeed: sh2
// preconditions:
// tail(snapshot) is a dead TaskNode
// tail(snapshot).next is PoolThreadNode
// tail(snapshot).next.next* is PoolThreadNode or null
// additional success postconditions: -
// failure postconditions: -
// post-actions (succeed):
// run state change ex2
// post-actions (fail):
// retry with new tail(snapshot)
if (tail.compareAndSetNext(tailNext, tailNextNext)) {
PoolThreadNode consumerNode = (PoolThreadNode) tailNext;
// state change ex2:
// tail(snapshot).next(snapshot).task ← runnable
// succeeds: ex1
// preconditions:
// tail(snapshot).next(snapshot).task = WAITING
// post-actions (succeed):
// unpark thread and return
// post-actions (fail):
// retry outer with new tail(snapshot)
if (consumerNode.compareAndSetTask(WAITING, runnable)) {
unpark(consumerNode.getThread());
result = EXE_OK;
break;
}
// otherwise the consumer gave up or was exited already, so fall out and...
}
// retry with new tail(snapshot) as was foretold
tail = this.tail;
if (UPDATE_STATISTICS) spinMisses.increment();
} else if (tailNext == null) {
// no consumers available; maybe we can start one
int tr = tryAllocateThread(growthResistance);
if (tr == AT_YES) {
result = EXE_CREATE_THREAD;
break;
}
if (tr == AT_SHUTDOWN) {
result = EXE_REJECT_SHUTDOWN;
break;
}
assert tr == AT_NO;
// no; try to enqueue
if (! NO_QUEUE_LIMIT && ! increaseQueueSize()) {
// queue is full
// OK last effort to create a thread, disregarding growth limit
tr = tryAllocateThread(0.0f);
if (tr == AT_YES) {
result = EXE_CREATE_THREAD;
break;
}
if (tr == AT_SHUTDOWN) {
result = EXE_REJECT_SHUTDOWN;
break;
}
assert tr == AT_NO;
result = EXE_REJECT_QUEUE_FULL;
break;
}
// queue size increased successfully; we can add to the list
TaskNode node = new TaskNode(runnable);
// state change ex5:
// tail(snapshot).next ← new task node
// cannot succeed: sh2
// preconditions:
// tail(snapshot).next = null
// ex3 failed precondition
// queue size increased to accommodate node
// postconditions (success):
// tail(snapshot).next = new task node
if (tail.compareAndSetNext(null, node)) {
// try to update tail to the new node; if this CAS fails then tail already points at past the node
// this is because tail can only ever move forward, and the task list is always strongly connected
compareAndSetTail(tail, node);
result = EXE_OK;
break;
}
// we failed; we have to drop the queue size back down again to compensate before we can retry
if (! NO_QUEUE_LIMIT) decreaseQueueSize();
// retry with new tail(snapshot)
tail = this.tail;
if (UPDATE_STATISTICS) spinMisses.increment();
} else {
// no consumers are waiting and the tail(snapshot).next node is non-null and not a task node, therefore it must be a...
assert tailNext instanceof TerminateWaiterNode;
// shutting down
result = EXE_REJECT_SHUTDOWN;
break;
}
}
return result;
}
// =======================================================
// Termination task
// =======================================================
void completeTermination() {
assert ! currentThreadHolds(headLock) && ! currentThreadHolds(tailLock);
// be kind and un-interrupt the thread for the termination task
Thread.interrupted();
final Runnable terminationTask = this.terminationTask;
this.terminationTask = null;
safeRun(terminationTask);
// notify all waiters
Waiter waiters = getAndSetTerminationWaiters(TERMINATE_COMPLETE_WAITER);
while (waiters != null) {
unpark(waiters.getThread());
waiters = waiters.getNext();
}
tail.setNext(TERMINATE_COMPLETE);
if (! DISABLE_MBEAN) {
final Object handle = this.handle;
if (handle != null) {
doPrivileged(new PrivilegedAction() {
public Void run() {
try {
ManagementFactory.getPlatformMBeanServer().unregisterMBean(((ObjectInstance)handle).getObjectName());
} catch (Throwable ignored) {
}
return null;
}
}, acc);
}
}
}
// =======================================================
// Compare-and-set operations
// =======================================================
void incrementActiveCount() {
unsafe.getAndAddInt(this, activeCountOffset, 1);
}
void decrementActiveCount() {
unsafe.getAndAddInt(this, activeCountOffset, -1);
}
boolean compareAndSetPeakThreadCount(final int expect, final int update) {
return unsafe.compareAndSwapInt(this, peakThreadCountOffset, expect, update);
}
boolean compareAndSetPeakQueueSize(final int expect, final int update) {
return unsafe.compareAndSwapInt(this, peakQueueSizeOffset, expect, update);
}
boolean compareAndSetQueueSize(final long expect, final long update) {
return unsafe.compareAndSwapLong(this, queueSizeOffset, expect, update);
}
boolean compareAndSetTerminationWaiters(final Waiter expect, final Waiter update) {
return unsafe.compareAndSwapObject(this, terminationWaitersOffset, expect, update);
}
Waiter getAndSetTerminationWaiters(final Waiter update) {
return (Waiter) unsafe.getAndSetObject(this, terminationWaitersOffset, update);
}
// =======================================================
// Queue size operations
// =======================================================
boolean increaseQueueSize() {
long oldVal = queueSize;
int oldSize = currentQueueSizeOf(oldVal);
if (oldSize >= maxQueueSizeOf(oldVal)) {
// reject
return false;
}
int newSize = oldSize + 1;
while (! compareAndSetQueueSize(oldVal, withCurrentQueueSize(oldVal, newSize))) {
if (UPDATE_STATISTICS) spinMisses.increment();
oldVal = queueSize;
oldSize = currentQueueSizeOf(oldVal);
if (oldSize >= maxQueueSizeOf(oldVal)) {
// reject
return false;
}
newSize = oldSize + 1;
}
if (UPDATE_STATISTICS) {
do {
// oldSize now represents the old peak size
oldSize = peakQueueSize;
if (newSize <= oldSize) break;
} while (! compareAndSetPeakQueueSize(oldSize, newSize));
}
return true;
}
void decreaseQueueSize() {
long oldVal;
oldVal = queueSize;
assert currentQueueSizeOf(oldVal) > 0;
while (! compareAndSetQueueSize(oldVal, withCurrentQueueSize(oldVal, currentQueueSizeOf(oldVal) - 1))) {
if (UPDATE_STATISTICS) spinMisses.increment();
oldVal = queueSize;
assert currentQueueSizeOf(oldVal) > 0;
}
}
// =======================================================
// Inline Functions
// =======================================================
static int currentQueueSizeOf(long queueSize) {
return (int) (queueSize & 0x7fff_ffff);
}
static long withCurrentQueueSize(long queueSize, int current) {
assert current >= 0;
return queueSize & 0xffff_ffff_0000_0000L | current;
}
static int maxQueueSizeOf(long queueSize) {
return (int) (queueSize >>> 32 & 0x7fff_ffff);
}
static long withMaxQueueSize(long queueSize, int max) {
assert max >= 0;
return queueSize & 0xffff_ffffL | (long)max << 32;
}
static int coreSizeOf(long status) {
return (int) (status >>> TS_CORE_SHIFT & TS_THREAD_CNT_MASK);
}
static int maxSizeOf(long status) {
return (int) (status >>> TS_MAX_SHIFT & TS_THREAD_CNT_MASK);
}
static int currentSizeOf(long status) {
return (int) (status >>> TS_CURRENT_SHIFT & TS_THREAD_CNT_MASK);
}
static long withCoreSize(long status, int newCoreSize) {
assert 0 <= newCoreSize && newCoreSize <= TS_THREAD_CNT_MASK;
return status & ~(TS_THREAD_CNT_MASK << TS_CORE_SHIFT) | (long)newCoreSize << TS_CORE_SHIFT;
}
static long withCurrentSize(long status, int newCurrentSize) {
assert 0 <= newCurrentSize && newCurrentSize <= TS_THREAD_CNT_MASK;
return status & ~(TS_THREAD_CNT_MASK << TS_CURRENT_SHIFT) | (long)newCurrentSize << TS_CURRENT_SHIFT;
}
static long withMaxSize(long status, int newMaxSize) {
assert 0 <= newMaxSize && newMaxSize <= TS_THREAD_CNT_MASK;
return status & ~(TS_THREAD_CNT_MASK << TS_MAX_SHIFT) | (long)newMaxSize << TS_MAX_SHIFT;
}
static long withShutdownRequested(final long status) {
return status | TS_SHUTDOWN_REQUESTED;
}
static long withShutdownComplete(final long status) {
return status | TS_SHUTDOWN_COMPLETE;
}
static long withShutdownInterrupt(final long status) {
return status | TS_SHUTDOWN_INTERRUPT;
}
static long withAllowCoreTimeout(final long status, final boolean allowed) {
return allowed ? status | TS_ALLOW_CORE_TIMEOUT : status & ~TS_ALLOW_CORE_TIMEOUT;
}
static boolean isShutdownRequested(final long status) {
return (status & TS_SHUTDOWN_REQUESTED) != 0;
}
static boolean isShutdownComplete(final long status) {
return (status & TS_SHUTDOWN_COMPLETE) != 0;
}
static boolean isShutdownInterrupt(final long threadStatus) {
return (threadStatus & TS_SHUTDOWN_INTERRUPT) != 0;
}
static boolean isAllowCoreTimeout(final long oldVal) {
return (oldVal & TS_ALLOW_CORE_TIMEOUT) != 0;
}
// =======================================================
// Locks
// =======================================================
private static boolean currentThreadHolds(final ExtendedLock lock) {
return lock.isHeldByCurrentThread();
}
// =======================================================
// Static configuration
// =======================================================
// =======================================================
// Utilities
// =======================================================
void safeRun(final Runnable task) {
assert ! currentThreadHolds(headLock) && ! currentThreadHolds(tailLock);
if (task == null) return;
final Thread currentThread = Thread.currentThread();
JBossExecutors.clearContextClassLoader(currentThread);
try {
task.run();
} catch (Throwable t) {
try {
exceptionHandler.uncaughtException(Thread.currentThread(), t);
} catch (Throwable ignored) {
// nothing else we can safely do here
}
} finally {
JBossExecutors.clearContextClassLoader(currentThread);
// clear interrupt status
Thread.interrupted();
}
}
void rejectException(final Runnable task, final Throwable cause) {
try {
handoffExecutor.execute(task);
} catch (Throwable t) {
t.addSuppressed(cause);
throw t;
}
}
void rejectNoThread(final Runnable task) {
try {
handoffExecutor.execute(task);
} catch (Throwable t) {
t.addSuppressed(new RejectedExecutionException("No threads available"));
throw t;
}
}
void rejectQueueFull(final Runnable task) {
try {
handoffExecutor.execute(task);
} catch (Throwable t) {
t.addSuppressed(new RejectedExecutionException("Queue is full"));
throw t;
}
}
void rejectShutdown(final Runnable task) {
try {
handoffExecutor.execute(task);
} catch (Throwable t) {
t.addSuppressed(new RejectedExecutionException("Executor is being shut down"));
throw t;
}
}
// =======================================================
// Node classes
// =======================================================
abstract static class QNode {
private static final long nextOffset;
static {
try {
nextOffset = unsafe.objectFieldOffset(QNode.class.getDeclaredField("next"));
} catch (NoSuchFieldException e) {
throw new NoSuchFieldError(e.getMessage());
}
}
@SuppressWarnings("unused")
private volatile QNode next;
QNode(final QNode next) {
this.next = next;
}
boolean compareAndSetNext(QNode expect, QNode update) {
return unsafe.compareAndSwapObject(this, nextOffset, expect, update);
}
QNode getNext() {
return next;
}
void setNext(final QNode node) {
next = node;
}
}
static final class PoolThreadNode extends QNode {
private static final long taskOffset;
static {
try {
taskOffset = unsafe.objectFieldOffset(PoolThreadNode.class.getDeclaredField("task"));
} catch (NoSuchFieldException e) {
throw new NoSuchFieldError(e.getMessage());
}
}
private final Thread thread;
@SuppressWarnings("unused")
private volatile Runnable task;
PoolThreadNode(final PoolThreadNode next, final Thread thread) {
super(next);
this.thread = thread;
task = WAITING;
}
Thread getThread() {
return thread;
}
boolean compareAndSetTask(final Runnable expect, final Runnable update) {
return unsafe.compareAndSwapObject(this, taskOffset, expect, update);
}
Runnable getTask() {
return task;
}
PoolThreadNode getNext() {
return (PoolThreadNode) super.getNext();
}
}
static final class TerminateWaiterNode extends QNode {
TerminateWaiterNode() {
super(null);
}
}
static final class TaskNode extends QNode {
volatile Runnable task;
TaskNode(final Runnable task) {
// we always start task nodes with a {@code null} next
super(null);
this.task = task;
}
Runnable getAndClearTask() {
try {
return task;
} finally {
this.task = null;
}
}
}
// =======================================================
// Management bean implementation
// =======================================================
final class MXBeanImpl implements StandardThreadPoolMXBean {
MXBeanImpl() {
}
public float getGrowthResistance() {
return EnhancedQueueExecutor.this.getGrowthResistance();
}
public void setGrowthResistance(final float value) {
EnhancedQueueExecutor.this.setGrowthResistance(value);
}
public boolean isGrowthResistanceSupported() {
return true;
}
public int getCorePoolSize() {
return EnhancedQueueExecutor.this.getCorePoolSize();
}
public void setCorePoolSize(final int corePoolSize) {
EnhancedQueueExecutor.this.setCorePoolSize(corePoolSize);
}
public boolean isCorePoolSizeSupported() {
return true;
}
public boolean prestartCoreThread() {
return EnhancedQueueExecutor.this.prestartCoreThread();
}
public int prestartAllCoreThreads() {
return EnhancedQueueExecutor.this.prestartAllCoreThreads();
}
public boolean isCoreThreadPrestartSupported() {
return true;
}
public int getMaximumPoolSize() {
return EnhancedQueueExecutor.this.getMaximumPoolSize();
}
public void setMaximumPoolSize(final int maxPoolSize) {
EnhancedQueueExecutor.this.setMaximumPoolSize(maxPoolSize);
}
public int getPoolSize() {
return EnhancedQueueExecutor.this.getPoolSize();
}
public int getLargestPoolSize() {
return EnhancedQueueExecutor.this.getLargestPoolSize();
}
public int getActiveCount() {
return EnhancedQueueExecutor.this.getActiveCount();
}
public boolean isAllowCoreThreadTimeOut() {
return EnhancedQueueExecutor.this.allowsCoreThreadTimeOut();
}
public void setAllowCoreThreadTimeOut(final boolean value) {
EnhancedQueueExecutor.this.allowCoreThreadTimeOut(value);
}
public long getKeepAliveTimeSeconds() {
return EnhancedQueueExecutor.this.getKeepAliveTime().getSeconds();
}
public void setKeepAliveTimeSeconds(final long seconds) {
EnhancedQueueExecutor.this.setKeepAliveTime(Duration.of(seconds, ChronoUnit.SECONDS));
}
public int getMaximumQueueSize() {
return EnhancedQueueExecutor.this.getMaximumQueueSize();
}
public void setMaximumQueueSize(final int size) {
EnhancedQueueExecutor.this.setMaximumQueueSize(size);
}
public int getQueueSize() {
return EnhancedQueueExecutor.this.getQueueSize();
}
public int getLargestQueueSize() {
return EnhancedQueueExecutor.this.getLargestQueueSize();
}
public boolean isQueueBounded() {
return ! NO_QUEUE_LIMIT;
}
public boolean isQueueSizeModifiable() {
return ! NO_QUEUE_LIMIT;
}
public boolean isShutdown() {
return EnhancedQueueExecutor.this.isShutdown();
}
public boolean isTerminating() {
return EnhancedQueueExecutor.this.isTerminating();
}
public boolean isTerminated() {
return EnhancedQueueExecutor.this.isTerminated();
}
public long getSubmittedTaskCount() {
return EnhancedQueueExecutor.this.getSubmittedTaskCount();
}
public long getRejectedTaskCount() {
return EnhancedQueueExecutor.this.getRejectedTaskCount();
}
public long getCompletedTaskCount() {
return EnhancedQueueExecutor.this.getCompletedTaskCount();
}
public long getSpinMissCount() {
return EnhancedQueueExecutor.this.spinMisses.longValue();
}
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/EnhancedQueueExecutorBase0.java 0000664 0000000 0000000 00000004124 13615100441 0031253 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2018 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import static java.security.AccessController.doPrivileged;
import java.security.PrivilegedAction;
import java.util.concurrent.AbstractExecutorService;
/**
* EQE base class: shared utilities and initial padding.
*/
abstract class EnhancedQueueExecutorBase0 extends AbstractExecutorService {
/**
* Padding fields.
*/
@SuppressWarnings("unused")
int p00, p01, p02, p03,
p04, p05, p06, p07,
p08, p09, p0A, p0B,
p0C, p0D, p0E, p0F;
EnhancedQueueExecutorBase0() {}
static boolean readBooleanPropertyPrefixed(String name, boolean defVal) {
return Boolean.parseBoolean(readPropertyPrefixed(name, Boolean.toString(defVal)));
}
static String readPropertyPrefixed(String name, String defVal) {
return readProperty("jboss.threads.eqe." + name, defVal);
}
static String readProperty(String name, String defVal) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
return doPrivileged(new PrivilegedAction() {
public String run() {
return readPropertyRaw(name, defVal);
}
});
} else {
return readPropertyRaw(name, defVal);
}
}
static String readPropertyRaw(final String name, final String defVal) {
return System.getProperty(name, defVal);
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/EnhancedQueueExecutorBase1.java 0000664 0000000 0000000 00000005515 13615100441 0031261 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2018 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import static org.jboss.threads.JBossExecutors.unsafe;
import org.wildfly.common.annotation.NotNull;
/**
* EQE base class: tail section.
*/
abstract class EnhancedQueueExecutorBase1 extends EnhancedQueueExecutorBase0 {
static final long tailOffset;
static {
try {
tailOffset = unsafe.objectFieldOffset(EnhancedQueueExecutorBase1.class.getDeclaredField("tail"));
} catch (NoSuchFieldException e) {
throw new NoSuchFieldError(e.getMessage());
}
}
// =======================================================
// Locks
// =======================================================
/**
* Establish a combined head/tail lock.
*/
static final boolean COMBINED_LOCK = readBooleanPropertyPrefixed("combined-lock", false);
/**
* Use a spin lock for the tail lock.
*/
static final boolean TAIL_SPIN = ! COMBINED_LOCK && readBooleanPropertyPrefixed("tail-spin", false);
/**
* Attempt to lock frequently-contended operations on the list tail. This defaults to {@code true} because
* moderate contention among 8 CPUs can result in thousands of spin misses per execution.
*/
static final boolean TAIL_LOCK = COMBINED_LOCK || readBooleanPropertyPrefixed("tail-lock", true);
// =======================================================
// Current state fields
// =======================================================
/**
* The node preceding the tail node; this field is not {@code null}. This
* is the insertion point for tasks (and the removal point for waiting threads).
*/
@NotNull
@SuppressWarnings("unused") // used by field updater
volatile EnhancedQueueExecutor.TaskNode tail;
EnhancedQueueExecutorBase1() {}
// =======================================================
// Compare-and-set operations
// =======================================================
void compareAndSetTail(final EnhancedQueueExecutor.TaskNode expect, final EnhancedQueueExecutor.TaskNode update) {
unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/EnhancedQueueExecutorBase2.java 0000664 0000000 0000000 00000002061 13615100441 0031253 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2018 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
/**
* EQE base class: padding.
*/
abstract class EnhancedQueueExecutorBase2 extends EnhancedQueueExecutorBase1 {
/**
* Padding fields.
*/
@SuppressWarnings("unused")
int p00, p01, p02, p03,
p04, p05, p06, p07,
p08, p09, p0A, p0B,
p0C, p0D, p0E, p0F;
EnhancedQueueExecutorBase2() {}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/EnhancedQueueExecutorBase3.java 0000664 0000000 0000000 00000005146 13615100441 0031263 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2018 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import static org.jboss.threads.JBossExecutors.unsafe;
import org.wildfly.common.annotation.NotNull;
/**
* EQE base class: head section.
*/
abstract class EnhancedQueueExecutorBase3 extends EnhancedQueueExecutorBase2 {
static final long headOffset;
static {
try {
headOffset = unsafe.objectFieldOffset(EnhancedQueueExecutorBase3.class.getDeclaredField("head"));
} catch (NoSuchFieldException e) {
throw new NoSuchFieldError(e.getMessage());
}
}
// =======================================================
// Locks
// =======================================================
/**
* Attempt to lock frequently-contended operations on the list head.
*/
static final boolean HEAD_LOCK = COMBINED_LOCK || readBooleanPropertyPrefixed("head-lock", true);
/**
* Use a spin lock for the head lock.
*/
static final boolean HEAD_SPIN = readBooleanPropertyPrefixed("head-spin", true);
// =======================================================
// Current state fields
// =======================================================
/**
* The node preceding the head node; this field is not {@code null}. This is
* the removal point for tasks (and the insertion point for waiting threads).
*/
@NotNull
@SuppressWarnings("unused") // used by field updater
volatile EnhancedQueueExecutor.TaskNode head;
EnhancedQueueExecutorBase3() {
head = tail = new EnhancedQueueExecutor.TaskNode(null);
}
// =======================================================
// Compare-and-set operations
// =======================================================
boolean compareAndSetHead(final EnhancedQueueExecutor.TaskNode expect, final EnhancedQueueExecutor.TaskNode update) {
return unsafe.compareAndSwapObject(this, headOffset, expect, update);
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/EnhancedQueueExecutorBase4.java 0000664 0000000 0000000 00000002061 13615100441 0031255 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2018 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
/**
* EQE base class: padding.
*/
abstract class EnhancedQueueExecutorBase4 extends EnhancedQueueExecutorBase3 {
/**
* Padding fields.
*/
@SuppressWarnings("unused")
int p00, p01, p02, p03,
p04, p05, p06, p07,
p08, p09, p0A, p0B,
p0C, p0D, p0E, p0F;
EnhancedQueueExecutorBase4() {}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/EnhancedQueueExecutorBase5.java 0000664 0000000 0000000 00000005265 13615100441 0031267 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2018, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.threads;
import static org.jboss.threads.JBossExecutors.unsafe;
/**
* EQE base: thread status
*/
abstract class EnhancedQueueExecutorBase5 extends EnhancedQueueExecutorBase4 {
static final long threadStatusOffset;
static {
try {
threadStatusOffset = unsafe.objectFieldOffset(EnhancedQueueExecutorBase5.class.getDeclaredField("threadStatus"));
} catch (NoSuchFieldException e) {
throw new NoSuchFieldError(e.getMessage());
}
}
// =======================================================
// Current state fields
// =======================================================
/**
* Active consumers:
*
* - Bit 00..19: current number of running threads
* - Bit 20..39: core pool size
* - Bit 40..59: maximum pool size
* - Bit 60: 1 = allow core thread timeout; 0 = disallow core thread timeout
* - Bit 61: 1 = shutdown requested; 0 = shutdown not requested
* - Bit 62: 1 = shutdown task interrupt requested; 0 = interrupt not requested
* - Bit 63: 1 = shutdown complete; 0 = shutdown not complete
*
*/
@SuppressWarnings("unused") // used by field updater
volatile long threadStatus;
EnhancedQueueExecutorBase5() {
super();
}
// =======================================================
// Compare-and-set operations
// =======================================================
boolean compareAndSetThreadStatus(final long expect, final long update) {
return unsafe.compareAndSwapLong(this, threadStatusOffset, expect, update);
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/EnhancedQueueExecutorBase6.java 0000664 0000000 0000000 00000002555 13615100441 0031267 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2018, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.threads;
/**
* EQE base class: padding.
*/
abstract class EnhancedQueueExecutorBase6 extends EnhancedQueueExecutorBase5 {
/**
* Padding fields.
*/
@SuppressWarnings("unused")
int p00, p01, p02, p03,
p04, p05, p06, p07,
p08, p09, p0A, p0B,
p0C, p0D, p0E, p0F;
EnhancedQueueExecutorBase6() {}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/HandoffRejectedExecutionHandler.java 0000664 0000000 0000000 00000002446 13615100441 0032351 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
class HandoffRejectedExecutionHandler implements RejectedExecutionHandler {
private final Executor target;
HandoffRejectedExecutionHandler(final Executor target) {
this.target = target;
}
public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) {
target.execute(r);
}
public String toString() {
return String.format("%s -> %s", super.toString(), target);
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/InterruptHandler.java 0000664 0000000 0000000 00000002261 13615100441 0027441 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
/**
* A thread interrupt handler. Called when a thread's {@code interrupt()} method is invoked. The handler should
* not throw an exception; otherwise user code might end up in an unexpected state.
*/
public interface InterruptHandler {
/**
* Handle an interrupt condition on the given thread. This method should not throw an exception.
*
* @param thread the thread which was interrupted
*/
void handleInterrupt(Thread thread);
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/JBossExecutors.java 0000664 0000000 0000000 00000035620 13615100441 0027076 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.lang.reflect.Field;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ScheduledExecutorService;
import java.security.PrivilegedAction;
import java.security.AccessController;
import org.jboss.logging.Logger;
import org.wildfly.common.Assert;
import sun.misc.Unsafe;
/**
* JBoss thread- and executor-related utility and factory methods.
*/
public final class JBossExecutors {
private static final Logger THREAD_ERROR_LOGGER = Logger.getLogger("org.jboss.threads.errors");
private JBossExecutors() {}
private static final RuntimePermission COPY_CONTEXT_CLASSLOADER_PERMISSION = new RuntimePermission("copyClassLoader");
private static final ExecutorService REJECTING_EXECUTOR_SERVICE = new DelegatingExecutorService(RejectingExecutor.INSTANCE);
private static final ExecutorService DISCARDING_EXECUTOR_SERVICE = new DelegatingExecutorService(DiscardingExecutor.INSTANCE);
// ==================================================
// DIRECT EXECUTORS
// ==================================================
/**
* Get the direct executor. This executor will immediately run any task it is given, and propagate back any
* run-time exceptions thrown.
*
* @return the direct executor instance
*/
public static Executor directExecutor() {
return SimpleDirectExecutor.INSTANCE;
}
/**
* Get the rejecting executor. This executor will reject any task submitted to it.
*
* @return the rejecting executor instance
*/
public static Executor rejectingExecutor() {
return RejectingExecutor.INSTANCE;
}
/**
* Get a rejecting executor. This executor will reject any task submitted to it with the given message.
*
* @param message the reject message
* @return the rejecting executor instance
*/
public static Executor rejectingExecutor(final String message) {
return new RejectingExecutor(message);
}
/**
* Get the rejecting executor service. This executor will reject any task submitted to it. It cannot be shut down.
*
* @return the rejecting executor service instance
*/
public static ExecutorService rejectingExecutorService() {
return REJECTING_EXECUTOR_SERVICE;
}
/**
* Get the rejecting executor service. This executor will reject any task submitted to it with the given message.
* It cannot be shut down.
*
* @param message the reject message
* @return the rejecting executor service instance
*/
public static ExecutorService rejectingExecutorService(final String message) {
return protectedExecutorService(rejectingExecutor(message));
}
/**
* Get the discarding executor. This executor will silently discard any task submitted to it.
*
* @return the discarding executor instance
*/
public static Executor discardingExecutor() {
return DiscardingExecutor.INSTANCE;
}
/**
* Get the discarding executor service. This executor will silently discard any task submitted to it. It cannot
* be shut down.
*
* @return the discarding executor service instance
*/
public static ExecutorService discardingExecutorService() {
return DISCARDING_EXECUTOR_SERVICE;
}
/**
* Create an executor which runs tasks with the given context class loader.
*
* @param delegate the executor to delegate to
* @param taskClassLoader the context class loader to use
* @return the new direct executor
*/
public static Executor contextClassLoaderExecutor(final Executor delegate, final ClassLoader taskClassLoader) {
return new DelegatingExecutor(delegate) {
public void execute(final Runnable command) {
super.execute(new ContextClassLoaderSavingRunnable(taskClassLoader, command));
}
};
}
// ==================================================
// REJECTED EXECUTION HANDLERS
// ==================================================
private static final RejectedExecutionHandler ABORT_POLICY = new ThreadPoolExecutor.AbortPolicy();
private static final RejectedExecutionHandler CALLER_RUNS_POLICY = new ThreadPoolExecutor.CallerRunsPolicy();
private static final RejectedExecutionHandler DISCARD_OLDEST_POLICY = new ThreadPoolExecutor.DiscardOldestPolicy();
private static final RejectedExecutionHandler DISCARD_POLICY = new ThreadPoolExecutor.DiscardPolicy();
/**
* Get the abort policy for a {@link java.util.concurrent.ThreadPoolExecutor}.
*
* @return the abort policy
* @see java.util.concurrent.ThreadPoolExecutor.AbortPolicy
*/
public static RejectedExecutionHandler abortPolicy() {
return ABORT_POLICY;
}
/**
* Get the caller-runs policy for a {@link java.util.concurrent.ThreadPoolExecutor}.
*
* @return the caller-runs policy
* @see java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy
*/
public static RejectedExecutionHandler callerRunsPolicy() {
return CALLER_RUNS_POLICY;
}
/**
* Get the discard-oldest policy for a {@link java.util.concurrent.ThreadPoolExecutor}.
*
* @return the discard-oldest policy
* @see java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy
*/
public static RejectedExecutionHandler discardOldestPolicy() {
return DISCARD_OLDEST_POLICY;
}
/**
* Get the discard policy for a {@link java.util.concurrent.ThreadPoolExecutor}.
*
* @return the discard policy
* @see java.util.concurrent.ThreadPoolExecutor.DiscardPolicy
*/
public static RejectedExecutionHandler discardPolicy() {
return DISCARD_POLICY;
}
/**
* Get a handoff policy for a {@link java.util.concurrent.ThreadPoolExecutor}. The returned instance will
* delegate to another executor in the event that the task is rejected.
*
* @param target the target executor
* @return the new handoff policy implementation
*/
public static RejectedExecutionHandler handoffPolicy(final Executor target) {
return new HandoffRejectedExecutionHandler(target);
}
// ==================================================
// PROTECTED EXECUTOR SERVICE WRAPPERS
// ==================================================
/**
* Wrap an executor with an {@code ExecutorService} instance which supports all the features of {@code ExecutorService}
* except for shutting down the executor.
*
* @param target the target executor
* @return the executor service
*/
public static ExecutorService protectedExecutorService(final Executor target) {
return new DelegatingExecutorService(target);
}
/**
* Wrap a scheduled executor with a {@code ScheduledExecutorService} instance which supports all the features of
* {@code ScheduledExecutorService} except for shutting down the executor.
*
* @param target the target executor
* @return the executor service
*/
public static ScheduledExecutorService protectedScheduledExecutorService(final ScheduledExecutorService target) {
return new DelegatingScheduledExecutorService(target);
}
// ==================================================
// THREAD FACTORIES
// ==================================================
/**
* Create a thread factory which resets all thread-local storage and delegates to the given thread factory.
* You must have the {@link RuntimePermission}{@code ("modifyThread")} permission to use this method.
*
* @param delegate the delegate thread factory
* @return the resetting thread factory
* @throws SecurityException if the caller does not have the {@link RuntimePermission}{@code ("modifyThread")}
* permission
*/
public static ThreadFactory resettingThreadFactory(final ThreadFactory delegate) throws SecurityException {
return new ThreadFactory() {
public Thread newThread(final Runnable r) {
return delegate.newThread(new ThreadLocalResettingRunnable(r));
}
};
}
private static final Runnable TCCL_RESETTER = new Runnable() {
public void run() {
Thread.currentThread().setContextClassLoader(null);
}
public String toString() {
return "ContextClassLoader-resetting Runnable";
}
};
// ==================================================
// RUNNABLES
// ==================================================
private static final Runnable NULL_RUNNABLE = NullRunnable.getInstance();
/**
* Get the null runnable which does nothing.
*
* @return the null runnable
*/
public static Runnable nullRunnable() {
return NULL_RUNNABLE;
}
/**
* Get a {@code Runnable} which, when executed, clears the thread context class loader (if the caller has sufficient
* privileges).
*
* @return the runnable
*/
public static Runnable contextClassLoaderResetter() {
return TCCL_RESETTER;
}
/**
* Create a task that delegates to the given task, preserving the context classloader which was in effect when
* this method was invoked.
*
* @param delegate the delegate runnable
* @return the wrapping runnable
* @throws SecurityException if a security manager exists and the caller does not have the {@code "copyClassLoader"}
* {@link RuntimePermission}.
*/
public static Runnable classLoaderPreservingTask(final Runnable delegate) throws SecurityException {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(COPY_CONTEXT_CLASSLOADER_PERMISSION);
}
return classLoaderPreservingTaskUnchecked(delegate);
}
static final ClassLoader SAFE_CL;
static {
ClassLoader safeClassLoader = JBossExecutors.class.getClassLoader();
if (safeClassLoader == null) {
safeClassLoader = ClassLoader.getSystemClassLoader();
}
if (safeClassLoader == null) {
safeClassLoader = new ClassLoader() {
};
}
SAFE_CL = safeClassLoader;
}
static Runnable classLoaderPreservingTaskUnchecked(final Runnable delegate) {
Assert.checkNotNullParam("delegate", delegate);
return new ContextClassLoaderSavingRunnable(getContextClassLoader(Thread.currentThread()), delegate);
}
static final Unsafe unsafe;
static final long contextClassLoaderOffs;
static {
unsafe = AccessController.doPrivileged(new PrivilegedAction() {
public Unsafe run() {
try {
final Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch (IllegalAccessException e) {
throw new IllegalAccessError(e.getMessage());
} catch (NoSuchFieldException e) {
throw new NoSuchFieldError(e.getMessage());
}
}
});
try {
contextClassLoaderOffs = unsafe.objectFieldOffset(Thread.class.getDeclaredField("contextClassLoader"));
} catch (NoSuchFieldException e) {
throw new NoSuchFieldError(e.getMessage());
}
}
/**
* Privileged method to get the context class loader of the given thread.
*
* @param thread the thread to introspect
* @return the context class loader
*/
static ClassLoader getContextClassLoader(final Thread thread) {
return (ClassLoader) unsafe.getObject(thread, contextClassLoaderOffs);
}
/**
* Privileged method to get and set the context class loader of the given thread.
*
* @param thread the thread to introspect
* @param newClassLoader the new context class loader
* @return the old context class loader
*/
static ClassLoader getAndSetContextClassLoader(final Thread thread, final ClassLoader newClassLoader) {
try {
return getContextClassLoader(thread);
} finally {
setContextClassLoader(thread, newClassLoader);
}
}
/**
* Privileged method to set the context class loader of the given thread.
*
* @param thread the thread to introspect
* @param classLoader the new context class loader
*/
static void setContextClassLoader(final Thread thread, final ClassLoader classLoader) {
unsafe.putObject(thread, contextClassLoaderOffs, classLoader);
}
/**
* Privileged method to clear the context class loader of the given thread to a safe non-{@code null} value.
*
* @param thread the thread to introspect
*/
static void clearContextClassLoader(final Thread thread) {
unsafe.putObject(thread, contextClassLoaderOffs, SAFE_CL);
}
// ==================================================
// UNCAUGHT EXCEPTION HANDLERS
// ==================================================
/**
* Get an uncaught exception handler which logs to the given logger.
*
* @param log the logger
* @return the handler
*/
public static Thread.UncaughtExceptionHandler loggingExceptionHandler(final Logger log) {
return new LoggingUncaughtExceptionHandler(log);
}
/**
* Get an uncaught exception handler which logs to the given logger.
*
* @param categoryName the name of the logger category to log to
* @return the handler
*/
public static Thread.UncaughtExceptionHandler loggingExceptionHandler(final String categoryName) {
return new LoggingUncaughtExceptionHandler(Logger.getLogger(categoryName));
}
private static final Thread.UncaughtExceptionHandler LOGGING_HANDLER = loggingExceptionHandler(THREAD_ERROR_LOGGER);
/**
* Get an uncaught exception handler which logs to the default error logger.
*
* @return the handler
*/
public static Thread.UncaughtExceptionHandler loggingExceptionHandler() {
return LOGGING_HANDLER;
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/JBossScheduledThreadPoolExecutor.java 0000664 0000000 0000000 00000010522 13615100441 0032510 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public final class JBossScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
private final AtomicInteger rejectCount = new AtomicInteger();
private final Runnable terminationTask;
public JBossScheduledThreadPoolExecutor(int corePoolSize, final Runnable terminationTask) {
super(corePoolSize);
this.terminationTask = terminationTask;
setRejectedExecutionHandler(super.getRejectedExecutionHandler());
}
public JBossScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, final Runnable terminationTask) {
super(corePoolSize, threadFactory);
this.terminationTask = terminationTask;
setRejectedExecutionHandler(super.getRejectedExecutionHandler());
}
public JBossScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler, final Runnable terminationTask) {
super(corePoolSize);
this.terminationTask = terminationTask;
setRejectedExecutionHandler(handler);
}
public JBossScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler, final Runnable terminationTask) {
super(corePoolSize, threadFactory);
this.terminationTask = terminationTask;
setRejectedExecutionHandler(handler);
}
public long getKeepAliveTime() {
return getKeepAliveTime(TimeUnit.MILLISECONDS);
}
public void setKeepAliveTime(final long milliseconds) {
super.setKeepAliveTime(milliseconds, TimeUnit.MILLISECONDS);
super.allowCoreThreadTimeOut(milliseconds < Long.MAX_VALUE);
}
public void setKeepAliveTime(final long time, final TimeUnit unit) {
super.setKeepAliveTime(time, unit);
super.allowCoreThreadTimeOut(time < Long.MAX_VALUE);
}
public int getRejectedCount() {
return rejectCount.get();
}
public int getCurrentThreadCount() {
return getActiveCount();
}
public int getLargestThreadCount() {
return getLargestPoolSize();
}
public int getMaxThreads() {
return getCorePoolSize();
}
public void setMaxThreads(final int newSize) {
setCorePoolSize(newSize);
}
public RejectedExecutionHandler getRejectedExecutionHandler() {
return ((CountingRejectHandler)super.getRejectedExecutionHandler()).getDelegate();
}
public void setRejectedExecutionHandler(final RejectedExecutionHandler handler) {
super.setRejectedExecutionHandler(new CountingRejectHandler(handler));
}
/** {@inheritDoc} */
public int getQueueSize() {
return this.getQueue().size();
}
protected void terminated() {
terminationTask.run();
}
private final class CountingRejectHandler implements RejectedExecutionHandler {
private final RejectedExecutionHandler delegate;
public CountingRejectHandler(final RejectedExecutionHandler delegate) {
this.delegate = delegate;
}
public RejectedExecutionHandler getDelegate() {
return delegate;
}
public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) {
rejectCount.incrementAndGet();
if (isShutdown()) {
throw Messages.msg.shutDownInitiated();
}
delegate.rejectedExecution(r, executor);
}
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/JBossThread.java 0000664 0000000 0000000 00000065231 13615100441 0026325 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
import org.wildfly.common.Assert;
import org.wildfly.common.function.ExceptionBiConsumer;
import org.wildfly.common.function.ExceptionBiFunction;
import org.wildfly.common.function.ExceptionConsumer;
import org.wildfly.common.function.ExceptionFunction;
import org.wildfly.common.function.ExceptionObjIntConsumer;
import org.wildfly.common.function.ExceptionObjLongConsumer;
import org.wildfly.common.function.ExceptionRunnable;
import org.wildfly.common.function.ExceptionSupplier;
import org.wildfly.common.function.Functions;
/**
* A JBoss thread. Supports logging and extra operations.
*/
public class JBossThread extends Thread {
private static final RuntimePermission MODIFY_THREAD_PERMISSION = new RuntimePermission("modifyThread");
static {
Version.getVersionString();
}
private volatile InterruptHandler interruptHandler;
private ThreadNameInfo threadNameInfo;
private List exitHandlers;
/**
* The thread is maybe interrupted. Possible transitions:
*
* - {@link #STATE_INTERRUPT_DEFERRED}
* - {@link #STATE_INTERRUPT_IN_PROGRESS}
*
*/
private static final int STATE_MAYBE_INTERRUPTED = 0;
/**
* The thread is not interrupted, and interrupts will be deferred. Possible transitions:
*
* - {@link #STATE_MAYBE_INTERRUPTED}
* - {@link #STATE_INTERRUPT_PENDING}
*
*/
private static final int STATE_INTERRUPT_DEFERRED = 1;
/**
* The thread is not interrupted, but there is an interrupt pending for once deferral is ended. Possible transitions:
*
* - {@link #STATE_INTERRUPT_IN_PROGRESS}
*
*/
private static final int STATE_INTERRUPT_PENDING = 2;
/**
* The thread is in the process of executing interruption logic. If the thread attempts to defer interrupts
* during this phase, it will block until the interruption logic is complete.
*/
private static final int STATE_INTERRUPT_IN_PROGRESS = 3;
private final AtomicInteger stateRef = new AtomicInteger();
/**
* Construct a new instance.
*
* @param target the runnable target
* @see Thread#Thread(Runnable)
*/
public JBossThread(final Runnable target) {
super(target);
}
/**
* Construct a new instance.
*
* @param target the runnable target
* @param name the initial thread name
* @see Thread#Thread(Runnable, String)
*/
public JBossThread(final Runnable target, final String name) {
super(target, name);
}
/**
* Construct a new instance.
*
* @param group the parent thread group
* @param target the runnable target
* @see Thread#Thread(ThreadGroup, Runnable)
* @throws SecurityException if the current thread cannot create a thread in the specified thread group
*/
public JBossThread(final ThreadGroup group, final Runnable target) throws SecurityException {
super(group, target);
}
/**
* Construct a new instance.
*
* @param group the parent thread group
* @param target the runnable target
* @param name the initial thread name
* @see Thread#Thread(ThreadGroup,Runnable,String)
* @throws SecurityException if the current thread cannot create a thread in the specified thread group
*/
public JBossThread(final ThreadGroup group, final Runnable target, final String name) throws SecurityException {
super(group, target, name);
}
/**
* Construct a new instance.
*
* @param group the parent thread group
* @param target the runnable target
* @param name the initial thread name
* @see Thread#Thread(ThreadGroup,Runnable,String,long)
* @throws SecurityException if the current thread cannot create a thread in the specified thread group
*/
public JBossThread(final ThreadGroup group, final Runnable target, final String name, final long stackSize) throws SecurityException {
super(group, target, name, stackSize);
}
/**
* Interrupt this thread. Logs a trace message and calls the current interrupt handler, if any. The interrupt
* handler is called from the calling thread, not the thread being interrupted.
*/
public void interrupt() {
final boolean differentThread = Thread.currentThread() != this;
if (differentThread) checkAccess();
// fast check
if (isInterrupted()) return;
final AtomicInteger stateRef = this.stateRef;
int oldVal, newVal;
do {
oldVal = stateRef.get();
if (oldVal == STATE_INTERRUPT_PENDING || oldVal == STATE_INTERRUPT_IN_PROGRESS) {
// already set
Messages.msg.tracef("Interrupting thread \"%s\" (already interrupted)", this);
return;
} else if (oldVal == STATE_INTERRUPT_DEFERRED) {
newVal = STATE_INTERRUPT_PENDING;
} else {
newVal = STATE_INTERRUPT_IN_PROGRESS;
}
} while (! stateRef.compareAndSet(oldVal, newVal));
if (newVal == STATE_INTERRUPT_IN_PROGRESS) try {
doInterrupt();
} finally {
// after we return, the thread could be un-interrupted at any time without our knowledge
stateRef.set(STATE_MAYBE_INTERRUPTED);
if (differentThread) {
// unpark the thread if it was waiting to defer interrupts
// interrupting the thread will unpark it; it might park after the interrupt though, or wake up before the state is restored
LockSupport.unpark(this);
}
} else {
Messages.intMsg.tracef("Interrupting thread \"%s\" (deferred)", this);
}
}
private void doInterrupt() {
if (isInterrupted()) return;
Messages.msg.tracef("Interrupting thread \"%s\"", this);
try {
super.interrupt();
} finally {
final InterruptHandler interruptHandler = this.interruptHandler;
if (interruptHandler != null) {
try {
interruptHandler.handleInterrupt(this);
} catch (Throwable t) {
Messages.msg.interruptHandlerThrew(t, interruptHandler);
}
}
}
}
public boolean isInterrupted() {
return this == Thread.currentThread() ? super.isInterrupted() : super.isInterrupted() || (stateRef.get() == STATE_INTERRUPT_PENDING);
}
/**
* Defer interrupts for the duration of some task. Once the task is complete, any deferred interrupt will be
* delivered to the thread, thus the thread interrupt status should be checked upon return. If the current thread
* is not a {@code JBossThread}, the task is simply run as-is.
*
* @param task the task to run
*/
public static void executeWithInterruptDeferred(final Runnable task) {
final JBossThread thread = currentThread();
if (registerDeferral(thread)) try {
task.run();
} finally {
unregisterDeferral(thread);
} else {
// already deferred
task.run();
}
}
/**
* Defer interrupts for the duration of some task. Once the task is complete, any deferred interrupt will be
* delivered to the thread, thus the thread interrupt status should be checked upon return. If the current thread
* is not a {@code JBossThread}, the task is simply run as-is.
*
* @param action the task to run
* @param the callable's return type
* @return the value returned from the callable
* @throws Exception if the action throws an exception
*/
public static T executeWithInterruptDeferred(final Callable action) throws Exception {
final JBossThread thread = currentThread();
if (registerDeferral(thread)) try {
return action.call();
} finally {
unregisterDeferral(thread);
} else {
// already deferred
return action.call();
}
}
/**
* Defer interrupts for the duration of some task. Once the task is complete, any deferred interrupt will be
* delivered to the thread, thus the thread interrupt status should be checked upon return. If the current thread
* is not a {@code JBossThread}, the task is simply run as-is.
*
* @param action the task to run
* @param the action's return type
* @return the value returned from the callable
*/
public static T executeWithInterruptDeferred(final PrivilegedAction action) {
final JBossThread thread = currentThread();
if (registerDeferral(thread)) try {
return action.run();
} finally {
unregisterDeferral(thread);
} else {
// already deferred
return action.run();
}
}
/**
* Defer interrupts for the duration of some task. Once the task is complete, any deferred interrupt will be
* delivered to the thread, thus the thread interrupt status should be checked upon return. If the current thread
* is not a {@code JBossThread}, the task is simply run as-is.
*
* @param action the task to run
* @param the action's return type
* @return the value returned from the callable
* @throws Exception if the action throws an exception
*/
public static T executeWithInterruptDeferred(final PrivilegedExceptionAction action) throws Exception {
final JBossThread thread = currentThread();
if (registerDeferral(thread)) try {
return action.run();
} finally {
unregisterDeferral(thread);
} else {
// already deferred
return action.run();
}
}
public static R applyInterruptDeferredEx(final ExceptionBiFunction function, T param1, U param2) throws E {
final JBossThread thread = currentThread();
if (registerDeferral(thread)) try {
return function.apply(param1, param2);
} finally {
unregisterDeferral(thread);
} else {
// already deferred
return function.apply(param1, param2);
}
}
public static R applyInterruptDeferredEx(final ExceptionFunction function, T param) throws E {
return applyInterruptDeferredEx(Functions.exceptionFunctionBiFunction(), function, param);
}
public static T getInterruptDeferredEx(final ExceptionSupplier supplier) throws E {
return applyInterruptDeferredEx(Functions.exceptionFunctionBiFunction(), Functions.exceptionSupplierFunction(), supplier);
}
public static void acceptInterruptDeferredEx(final ExceptionObjLongConsumer consumer, T param1, long param2) throws E {
final JBossThread thread = currentThread();
if (registerDeferral(thread)) try {
consumer.accept(param1, param2);
} finally {
unregisterDeferral(thread);
} else {
// already deferred
consumer.accept(param1, param2);
}
}
public static void acceptInterruptDeferredEx(final ExceptionObjIntConsumer consumer, T param1, int param2) throws E {
final JBossThread thread = currentThread();
if (registerDeferral(thread)) try {
consumer.accept(param1, param2);
} finally {
unregisterDeferral(thread);
} else {
// already deferred
consumer.accept(param1, param2);
}
}
public static void acceptInterruptDeferredEx(final ExceptionBiConsumer consumer, T param1, U param2) throws E {
final JBossThread thread = currentThread();
if (registerDeferral(thread)) try {
consumer.accept(param1, param2);
} finally {
unregisterDeferral(thread);
} else {
// already deferred
consumer.accept(param1, param2);
}
}
public static void acceptInterruptDeferredEx(final ExceptionConsumer consumer, T param) throws E {
acceptInterruptDeferredEx(Functions.exceptionConsumerBiConsumer(), consumer, param);
}
public static void runInterruptDeferredEx(final ExceptionRunnable runnable) throws E {
acceptInterruptDeferredEx(Functions.exceptionConsumerBiConsumer(), Functions.exceptionRunnableConsumer(), runnable);
}
public static R applyInterruptResumedEx(final ExceptionBiFunction function, T param1, U param2) throws E {
final JBossThread thread = currentThread();
if (unregisterDeferral(thread)) try {
return function.apply(param1, param2);
} finally {
registerDeferral(thread);
} else {
// already resumed
return function.apply(param1, param2);
}
}
public static R applyInterruptResumedEx(final ExceptionFunction function, T param) throws E {
return applyInterruptResumedEx(Functions.exceptionFunctionBiFunction(), function, param);
}
public static T getInterruptResumedEx(final ExceptionSupplier supplier) throws E {
return applyInterruptResumedEx(Functions.exceptionFunctionBiFunction(), Functions.exceptionSupplierFunction(), supplier);
}
public static void acceptInterruptResumedEx(final ExceptionObjLongConsumer consumer, T param1, long param2) throws E {
final JBossThread thread = currentThread();
if (unregisterDeferral(thread)) try {
consumer.accept(param1, param2);
} finally {
registerDeferral(thread);
} else {
// already resumed
consumer.accept(param1, param2);
}
}
public static void acceptInterruptResumedEx(final ExceptionObjIntConsumer consumer, T param1, int param2) throws E {
final JBossThread thread = currentThread();
if (unregisterDeferral(thread)) try {
consumer.accept(param1, param2);
} finally {
registerDeferral(thread);
} else {
// already resumed
consumer.accept(param1, param2);
}
}
public static void acceptInterruptResumedEx(final ExceptionBiConsumer consumer, T param1, U param2) throws E {
final JBossThread thread = currentThread();
if (unregisterDeferral(thread)) try {
consumer.accept(param1, param2);
} finally {
registerDeferral(thread);
} else {
// already resumed
consumer.accept(param1, param2);
}
}
public static void acceptInterruptResumedEx(final ExceptionConsumer consumer, T param) throws E {
acceptInterruptResumedEx(Functions.exceptionConsumerBiConsumer(), consumer, param);
}
public static void runInterruptResumedEx(final ExceptionRunnable runnable) throws E {
acceptInterruptResumedEx(Functions.exceptionConsumerBiConsumer(), Functions.exceptionRunnableConsumer(), runnable);
}
private static boolean unregisterDeferral(final JBossThread thread) {
if (thread == null) {
return false;
}
int oldVal, newVal;
final AtomicInteger stateRef = thread.stateRef;
do {
oldVal = stateRef.get();
if (oldVal == STATE_MAYBE_INTERRUPTED || oldVal == STATE_INTERRUPT_IN_PROGRESS) {
// already not deferred
return false;
} else if (oldVal == STATE_INTERRUPT_DEFERRED) {
newVal = STATE_MAYBE_INTERRUPTED;
} else if (oldVal == STATE_INTERRUPT_PENDING) {
newVal = STATE_INTERRUPT_IN_PROGRESS;
} else {
throw Assert.unreachableCode();
}
} while (! stateRef.compareAndSet(oldVal, newVal));
if (newVal == STATE_INTERRUPT_IN_PROGRESS) try {
thread.doInterrupt();
} finally {
stateRef.set(STATE_MAYBE_INTERRUPTED);
}
return true;
}
private static boolean registerDeferral(final JBossThread thread) {
if (thread == null) {
return false;
}
final AtomicInteger stateRef = thread.stateRef;
int oldVal, newVal;
do {
oldVal = stateRef.get();
while (oldVal == STATE_INTERRUPT_IN_PROGRESS) {
LockSupport.park();
oldVal = stateRef.get();
}
if (oldVal == STATE_MAYBE_INTERRUPTED) {
newVal = Thread.interrupted() ? STATE_INTERRUPT_DEFERRED : STATE_INTERRUPT_PENDING;
} else if (oldVal == STATE_INTERRUPT_DEFERRED || oldVal == STATE_INTERRUPT_PENDING) {
// already deferred
return false;
} else {
throw Assert.unreachableCode();
}
} while (! stateRef.compareAndSet(oldVal, newVal));
if (newVal == STATE_INTERRUPT_DEFERRED && Thread.interrupted()) {
// in case we got interrupted right after we checked interrupt state but before we CAS'd the value.
stateRef.set(STATE_INTERRUPT_PENDING);
}
return true;
}
/**
* Execute the thread's {@code Runnable}. Logs a trace message at the start and end of execution and runs exit
* handlers when the thread exits.
*/
public void run() {
Messages.msg.tracef("Thread \"%s\" starting execution", this);
try {
super.run();
} finally {
Messages.msg.tracef("Thread \"%s\" exiting", this);
final List exitHandlers = this.exitHandlers;
if (exitHandlers != null) for (Runnable exitHandler : exitHandlers) {
try {
exitHandler.run();
} catch (Throwable t) {
try {
getUncaughtExceptionHandler().uncaughtException(this, t);
} catch (Throwable ignored) {}
}
}
}
}
/**
* Register a runnable task to be executed when the current thread exits.
*
* @param hook the task to run
* @return {@code true} if the task was registered; {@code false} if the task is {@code null} or if the current
* thread is not an instance of {@code JBossThread}
* @throws SecurityException if a security manager is installed and the caller's security context lacks the
* {@code modifyThread} {@link RuntimePermission}
*/
public static boolean onExit(Runnable hook) throws SecurityException {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(MODIFY_THREAD_PERMISSION);
}
final JBossThread thread = currentThread();
if (thread == null || hook == null) return false;
List exitHandlers = thread.exitHandlers;
if (exitHandlers == null) {
exitHandlers = new ArrayList<>();
thread.exitHandlers = exitHandlers;
}
exitHandlers.add(new ContextClassLoaderSavingRunnable(JBossExecutors.getContextClassLoader(thread), hook));
return true;
}
/**
* Get the current {@code JBossThread}, or {@code null} if the current thread is not a {@code JBossThread}.
*
* @return the current thread, or {@code null}
*/
public static JBossThread currentThread() {
final Thread thread = Thread.currentThread();
return thread instanceof JBossThread ? (JBossThread) thread : null;
}
/**
* Start the thread.
*
* @throws IllegalThreadStateException if the thread was already started.
*/
public void start() {
super.start();
Messages.msg.tracef("Started thread \"%s\"", this);
}
/**
* Change the uncaught exception handler for this thread.
*
* @param eh the new handler
*/
public void setUncaughtExceptionHandler(final UncaughtExceptionHandler eh) {
super.setUncaughtExceptionHandler(eh);
Messages.msg.tracef("Changed uncaught exception handler for \"%s\" to %s", this, eh);
}
/**
* Swap the current thread's active interrupt handler. Most callers should restore the old handler in a {@code finally}
* block like this:
*
* InterruptHandler oldHandler = JBossThread.getAndSetInterruptHandler(newHandler);
* try {
* ...execute interrupt-sensitive operation...
* } finally {
* JBossThread.getAndSetInterruptHandler(oldHandler);
* }
*
*
* @param newInterruptHandler the new interrupt handler
* @return the old interrupt handler
*/
public static InterruptHandler getAndSetInterruptHandler(final InterruptHandler newInterruptHandler) {
final JBossThread thread = currentThread();
if (thread == null) {
throw Messages.msg.noInterruptHandlers();
}
try {
return thread.interruptHandler;
} finally {
thread.interruptHandler = newInterruptHandler;
}
}
public static R applyWithInterruptHandler(InterruptHandler interruptHandler, ExceptionBiFunction function, T param1, U param2) throws E {
final JBossThread thread = currentThread();
if (thread == null) {
return function.apply(param1, param2);
} else {
final InterruptHandler old = thread.interruptHandler;
thread.interruptHandler = interruptHandler;
try {
return function.apply(param1, param2);
} finally {
thread.interruptHandler = old;
}
}
}
public static R applyWithInterruptHandler(InterruptHandler interruptHandler, ExceptionFunction function, T param1) throws E {
return applyWithInterruptHandler(interruptHandler, Functions.exceptionFunctionBiFunction(), function, param1);
}
public static R getWithInterruptHandler(InterruptHandler interruptHandler, ExceptionSupplier function) throws E {
return applyWithInterruptHandler(interruptHandler, Functions.exceptionFunctionBiFunction(), Functions.exceptionSupplierFunction(), function);
}
public static void acceptWithInterruptHandler(InterruptHandler interruptHandler, ExceptionObjLongConsumer function, T param1, long param2) throws E {
final JBossThread thread = currentThread();
if (thread == null) {
function.accept(param1, param2);
return;
} else {
final InterruptHandler old = thread.interruptHandler;
thread.interruptHandler = interruptHandler;
try {
function.accept(param1, param2);
return;
} finally {
thread.interruptHandler = old;
}
}
}
public static void acceptWithInterruptHandler(InterruptHandler interruptHandler, ExceptionObjIntConsumer function, T param1, int param2) throws E {
final JBossThread thread = currentThread();
if (thread == null) {
function.accept(param1, param2);
return;
} else {
final InterruptHandler old = thread.interruptHandler;
thread.interruptHandler = interruptHandler;
try {
function.accept(param1, param2);
return;
} finally {
thread.interruptHandler = old;
}
}
}
public static void acceptWithInterruptHandler(InterruptHandler interruptHandler, ExceptionBiConsumer function, T param1, U param2) throws E {
final JBossThread thread = currentThread();
if (thread == null) {
function.accept(param1, param2);
return;
} else {
final InterruptHandler old = thread.interruptHandler;
thread.interruptHandler = interruptHandler;
try {
function.accept(param1, param2);
return;
} finally {
thread.interruptHandler = old;
}
}
}
public static void acceptWithInterruptHandler(InterruptHandler interruptHandler, ExceptionConsumer function, T param1) throws E {
acceptWithInterruptHandler(interruptHandler, Functions.exceptionConsumerBiConsumer(), function, param1);
}
public static void runWithInterruptHandler(InterruptHandler interruptHandler, ExceptionRunnable function) throws E {
acceptWithInterruptHandler(interruptHandler, Functions.exceptionConsumerBiConsumer(), Functions.exceptionRunnableConsumer(), function);
}
/**
* Get the thread name information. This includes information about the thread's sequence number and so forth.
*
* @return the thread name info
*/
ThreadNameInfo getThreadNameInfo() {
return threadNameInfo;
}
/**
* Set the thread name information. This includes information about the thread's sequence number and so forth.
*
* @param threadNameInfo the new thread name info
* @throws SecurityException if the calling thread is not allowed to modify this thread
*/
void setThreadNameInfo(final ThreadNameInfo threadNameInfo) throws SecurityException {
checkAccess();
this.threadNameInfo = threadNameInfo;
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/JBossThreadFactory.java 0000664 0000000 0000000 00000012427 13615100441 0027654 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.AccessControlContext;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
/**
* A factory for {@link JBossThread} instances.
*/
public final class JBossThreadFactory implements ThreadFactory {
private final ThreadGroup threadGroup;
private final Boolean daemon;
private final Integer initialPriority;
private final Thread.UncaughtExceptionHandler uncaughtExceptionHandler;
private final Long stackSize;
private final String namePattern;
private final AtomicLong factoryThreadIndexSequence = new AtomicLong(1L);
private final long factoryIndex;
private final AccessControlContext creatingContext;
private static final AtomicLong globalThreadIndexSequence = new AtomicLong(1L);
private static final AtomicLong factoryIndexSequence = new AtomicLong(1L);
/**
* Construct a new instance. The access control context of the calling thread will be the one used to create
* new threads if a security manager is installed.
*
* @param threadGroup the thread group to assign threads to by default (may be {@code null})
* @param daemon whether the created threads should be daemon threads, or {@code null} to use the thread group's setting
* @param initialPriority the initial thread priority, or {@code null} to use the thread group's setting
* @param namePattern the name pattern string
* @param uncaughtExceptionHandler the uncaught exception handler, if any
* @param stackSize the JVM-specific stack size, or {@code null} to leave it unspecified
*/
public JBossThreadFactory(ThreadGroup threadGroup, final Boolean daemon, final Integer initialPriority, String namePattern, final Thread.UncaughtExceptionHandler uncaughtExceptionHandler, final Long stackSize) {
if (threadGroup == null) {
final SecurityManager sm = System.getSecurityManager();
threadGroup = sm != null ? sm.getThreadGroup() : Thread.currentThread().getThreadGroup();
}
this.threadGroup = threadGroup;
this.daemon = daemon;
this.initialPriority = initialPriority;
this.uncaughtExceptionHandler = uncaughtExceptionHandler;
this.stackSize = stackSize;
factoryIndex = factoryIndexSequence.getAndIncrement();
if (namePattern == null) {
namePattern = "pool-%f-thread-%t";
}
this.namePattern = namePattern;
this.creatingContext = AccessController.getContext();
}
/**
* @deprecated Use {@link #JBossThreadFactory(ThreadGroup, Boolean, Integer, String, Thread.UncaughtExceptionHandler, Long)} instead.
*/
public JBossThreadFactory(ThreadGroup threadGroup, final Boolean daemon, final Integer initialPriority, String namePattern, final Thread.UncaughtExceptionHandler uncaughtExceptionHandler, final Long stackSize, final AccessControlContext ignored) {
this(threadGroup, daemon, initialPriority, namePattern, uncaughtExceptionHandler, stackSize);
}
public Thread newThread(final Runnable target) {
final AccessControlContext context;
if ((context = creatingContext) != null) {
return AccessController.doPrivileged(new ThreadCreateAction(target), context);
} else {
return createThread(target);
}
}
private final class ThreadCreateAction implements PrivilegedAction {
private final Runnable target;
private ThreadCreateAction(final Runnable target) {
this.target = target;
}
public Thread run() {
return createThread(target);
}
}
private Thread createThread(final Runnable target) {
final ThreadNameInfo nameInfo = new ThreadNameInfo(globalThreadIndexSequence.getAndIncrement(), factoryThreadIndexSequence.getAndIncrement(), factoryIndex);
final JBossThread thread;
if (stackSize != null) {
thread = new JBossThread(threadGroup, target, "", stackSize.longValue());
} else {
thread = new JBossThread(threadGroup, target);
}
thread.setThreadNameInfo(nameInfo);
thread.setName(nameInfo.format(thread, namePattern));
if (initialPriority != null) thread.setPriority(initialPriority.intValue());
if (daemon != null) thread.setDaemon(daemon.booleanValue());
if (uncaughtExceptionHandler != null) thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
JBossExecutors.clearContextClassLoader(thread);
return thread;
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/JDKSpecific.java 0000664 0000000 0000000 00000002700 13615100441 0026223 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2018 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.concurrent.TimeUnit;
import org.wildfly.common.Assert;
/**
*/
final class JDKSpecific {
static TemporalUnit timeToTemporal(final TimeUnit timeUnit) {
switch (timeUnit) {
case NANOSECONDS: return ChronoUnit.NANOS;
case MICROSECONDS: return ChronoUnit.MICROS;
case MILLISECONDS: return ChronoUnit.MILLIS;
case SECONDS: return ChronoUnit.SECONDS;
case MINUTES: return ChronoUnit.MINUTES;
case HOURS: return ChronoUnit.HOURS;
case DAYS: return ChronoUnit.DAYS;
default: throw Assert.impossibleSwitchCase(timeUnit);
}
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/LoggingUncaughtExceptionHandler.java 0000664 0000000 0000000 00000002355 13615100441 0032415 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import org.jboss.logging.Logger;
class LoggingUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private final Logger log;
LoggingUncaughtExceptionHandler(final Logger log) {
this.log = log;
}
public void uncaughtException(final Thread thread, final Throwable throwable) {
log.errorf(throwable, "Thread %s threw an uncaught exception", thread);
}
public String toString() {
return String.format("%s to \"%s\"", super.toString(), log.getName());
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/ManagedThreadPoolExecutor.java 0000664 0000000 0000000 00000016716 13615100441 0031216 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.jboss.threads.management.ManageableThreadPoolExecutorService;
import org.jboss.threads.management.StandardThreadPoolMXBean;
import org.wildfly.common.Assert;
/**
* A version of {@link ThreadPoolExecutor} which implements {@link ManageableThreadPoolExecutorService} in order to allow
* opting out of using {@link EnhancedQueueExecutor}.
*/
public final class ManagedThreadPoolExecutor extends ThreadPoolExecutor implements ManageableThreadPoolExecutorService {
private final Runnable terminationTask;
private final StandardThreadPoolMXBean mxBean = new MXBeanImpl();
private volatile Executor handoffExecutor = JBossExecutors.rejectingExecutor();
private static final RejectedExecutionHandler HANDLER = new RejectedExecutionHandler() {
public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) {
((ManagedThreadPoolExecutor) executor).reject(r);
}
};
public ManagedThreadPoolExecutor(final int corePoolSize, final int maximumPoolSize, final long keepAliveTime, final TimeUnit unit, final BlockingQueue workQueue, final Runnable terminationTask) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, HANDLER);
this.terminationTask = terminationTask;
}
public ManagedThreadPoolExecutor(final int corePoolSize, final int maximumPoolSize, final long keepAliveTime, final TimeUnit unit, final BlockingQueue workQueue, final ThreadFactory threadFactory, final Runnable terminationTask) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, HANDLER);
this.terminationTask = terminationTask;
}
public ManagedThreadPoolExecutor(final int corePoolSize, final int maximumPoolSize, final long keepAliveTime, final TimeUnit unit, final BlockingQueue workQueue, final Executor handoffExecutor, final Runnable terminationTask) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, HANDLER);
this.terminationTask = terminationTask;
this.handoffExecutor = handoffExecutor;
}
public ManagedThreadPoolExecutor(final int corePoolSize, final int maximumPoolSize, final long keepAliveTime, final TimeUnit unit, final BlockingQueue workQueue, final ThreadFactory threadFactory, final Executor handoffExecutor, final Runnable terminationTask) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, HANDLER);
this.terminationTask = terminationTask;
this.handoffExecutor = handoffExecutor;
}
public StandardThreadPoolMXBean getThreadPoolMXBean() {
return mxBean;
}
public Executor getHandoffExecutor() {
return handoffExecutor;
}
public void setHandoffExecutor(final Executor handoffExecutor) {
Assert.checkNotNullParam("handoffExecutor", handoffExecutor);
this.handoffExecutor = handoffExecutor;
super.setRejectedExecutionHandler(HANDLER);
}
void reject(Runnable r) {
handoffExecutor.execute(r);
}
protected void terminated() {
terminationTask.run();
}
class MXBeanImpl implements StandardThreadPoolMXBean {
public float getGrowthResistance() {
return 1.0f;
}
public void setGrowthResistance(final float value) {
// ignored
}
public boolean isGrowthResistanceSupported() {
return false;
}
public int getCorePoolSize() {
return ManagedThreadPoolExecutor.this.getCorePoolSize();
}
public void setCorePoolSize(final int corePoolSize) {
ManagedThreadPoolExecutor.this.setCorePoolSize(corePoolSize);
}
public boolean isCorePoolSizeSupported() {
return true;
}
public boolean prestartCoreThread() {
return ManagedThreadPoolExecutor.this.prestartCoreThread();
}
public int prestartAllCoreThreads() {
return ManagedThreadPoolExecutor.this.prestartAllCoreThreads();
}
public boolean isCoreThreadPrestartSupported() {
return true;
}
public int getMaximumPoolSize() {
return ManagedThreadPoolExecutor.this.getMaximumPoolSize();
}
public void setMaximumPoolSize(final int maxPoolSize) {
ManagedThreadPoolExecutor.this.setMaximumPoolSize(maxPoolSize);
}
public int getPoolSize() {
return ManagedThreadPoolExecutor.this.getPoolSize();
}
public int getLargestPoolSize() {
return ManagedThreadPoolExecutor.this.getLargestPoolSize();
}
public int getActiveCount() {
return ManagedThreadPoolExecutor.this.getActiveCount();
}
public boolean isAllowCoreThreadTimeOut() {
return ManagedThreadPoolExecutor.this.allowsCoreThreadTimeOut();
}
public void setAllowCoreThreadTimeOut(final boolean value) {
ManagedThreadPoolExecutor.this.allowCoreThreadTimeOut(value);
}
public long getKeepAliveTimeSeconds() {
return ManagedThreadPoolExecutor.this.getKeepAliveTime(TimeUnit.SECONDS);
}
public void setKeepAliveTimeSeconds(final long seconds) {
ManagedThreadPoolExecutor.this.setKeepAliveTime(seconds, TimeUnit.SECONDS);
}
public int getMaximumQueueSize() {
return 0;
}
public void setMaximumQueueSize(final int size) {
}
public int getQueueSize() {
return ManagedThreadPoolExecutor.this.getQueue().size();
}
public int getLargestQueueSize() {
return 0;
}
public boolean isQueueBounded() {
return false;
}
public boolean isQueueSizeModifiable() {
return false;
}
public boolean isShutdown() {
return ManagedThreadPoolExecutor.this.isShutdown();
}
public boolean isTerminating() {
return ManagedThreadPoolExecutor.this.isTerminating();
}
public boolean isTerminated() {
return ManagedThreadPoolExecutor.this.isTerminated();
}
public long getSubmittedTaskCount() {
return ManagedThreadPoolExecutor.this.getTaskCount();
}
public long getRejectedTaskCount() {
return 0;
}
public long getCompletedTaskCount() {
return ManagedThreadPoolExecutor.this.getCompletedTaskCount();
}
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/Messages.java 0000664 0000000 0000000 00000007647 13615100441 0025733 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.threads;
import org.jboss.logging.BasicLogger;
import org.jboss.logging.Logger;
import org.jboss.logging.annotations.Cause;
import org.jboss.logging.annotations.LogMessage;
import org.jboss.logging.annotations.Message;
import org.jboss.logging.annotations.MessageLogger;
/**
* @author David M. Lloyd
*/
@MessageLogger(projectCode = "JBTHR", length = 5)
interface Messages extends BasicLogger {
Messages msg = Logger.getMessageLogger(Messages.class, "org.jboss.threads");
Messages intMsg = Logger.getMessageLogger(Messages.class, "org.jboss.threads.interrupt-handler");
// version
@Message(value = "JBoss Threads version %s")
@LogMessage(level = Logger.Level.INFO)
void version(String version);
// execution
// @Message(id = 1, value = "Thread factory did not produce a thread")
// @Message(id = 2, value = "Task limit reached")
// @Message(id = 3, value = "Operation timed out")
// @Message(id = 4, value = "Operation was cancelled")
// @Message(id = 5, value = "Operation failed")
// @Message(id = 6, value = "Unable to add new thread to the running set")
// @Message(id = 7, value = "Task execution interrupted")
// @Message(id = 8, value = "Task rejected")
@Message(id = 9, value = "Executor has been shut down")
StoppedExecutorException shutDownInitiated();
// @Message(id = 10, value = "Task execution timed out")
// @Message(id = 11, value = "Task execution failed for task %s")
@Message(id = 12, value = "Cannot await termination of a thread pool from one of its own threads")
IllegalStateException cannotAwaitWithin();
// @Message(id = 13, value = "No executors available to run task")
// @Message(id = 14, value = "Error submitting task %s to executor")
// validation
// @Message(id = 100, value = "Keep-alive may only be set to 0 for this executor type")
// @Message(id = 101, value = "Cannot reduce maximum threads below current thread number of running threads")
// @Message(id = 102, value = "Empty array parameter is not empty")
@Message(id = 103, value = "The current thread does not support interrupt handlers")
IllegalStateException noInterruptHandlers();
@Message(id = 104, value = "Executor is not shut down")
@Deprecated
IllegalStateException notShutDown();
// @Message(id = 105, value = "Concurrent modification of collection detected")
// @Message(id = 106, value = "No such element (iteration past end)")
// @Message(id = 107, value = "Unknown throwable received")
@Message(id = 108, value = "Interrupt handler %s threw an exception")
@LogMessage(level = Logger.Level.ERROR)
void interruptHandlerThrew(@Cause Throwable cause, InterruptHandler interruptHandler);
// security
@Message(id = 200, value = "%s() not allowed on container-managed executor")
SecurityException notAllowedContainerManaged(String methodName);
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/NullRunnable.java 0000664 0000000 0000000 00000001760 13615100441 0026553 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
final class NullRunnable implements Runnable {
private static final NullRunnable INSTANCE = new NullRunnable();
static NullRunnable getInstance() {
return INSTANCE;
}
NullRunnable() {
}
public void run() {
// do nothing
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/RejectingExecutor.java 0000664 0000000 0000000 00000002452 13615100441 0027602 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
class RejectingExecutor implements Executor {
static final RejectingExecutor INSTANCE = new RejectingExecutor();
private final String message;
private RejectingExecutor() {
message = null;
}
RejectingExecutor(final String message) {
this.message = message;
}
public void execute(final Runnable command) {
throw new RejectedExecutionException(message);
}
public String toString() {
return "Rejecting executor";
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/SimpleDirectExecutor.java 0000664 0000000 0000000 00000002114 13615100441 0030247 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.util.concurrent.Executor;
class SimpleDirectExecutor implements Executor {
static final SimpleDirectExecutor INSTANCE = new SimpleDirectExecutor();
private SimpleDirectExecutor() {
}
public void execute(final Runnable command) {
command.run();
}
public String toString() {
return "Direct executor";
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/StoppedExecutorException.java 0000664 0000000 0000000 00000004730 13615100441 0031166 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.util.concurrent.RejectedExecutionException;
/**
* Thrown when a task is submitted to an executor which is in the process of, or has completed shutting down.
*/
public class StoppedExecutorException extends RejectedExecutionException {
private static final long serialVersionUID = 4815103522815471074L;
/**
* Constructs a {@code StoppedExecutorException} with no detail message. The cause is not initialized, and may
* subsequently be initialized by a call to {@link #initCause(Throwable) initCause}.
*/
public StoppedExecutorException() {
}
/**
* Constructs a {@code StoppedExecutorException} with the specified detail message. The cause is not initialized, and
* may subsequently be initialized by a call to {@link #initCause(Throwable) initCause}.
*
* @param msg the detail message
*/
public StoppedExecutorException(final String msg) {
super(msg);
}
/**
* Constructs a {@code StoppedExecutorException} with the specified cause. The detail message is set to:
* (cause == null ? null : cause.toString())
* (which typically contains the class and detail message of {@code cause}).
*
* @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method)
*/
public StoppedExecutorException(final Throwable cause) {
super(cause);
}
/**
* Constructs a {@code StoppedExecutorException} with the specified detail message and cause.
*
* @param msg the detail message
* @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method)
*/
public StoppedExecutorException(final String msg, final Throwable cause) {
super(msg, cause);
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/Substitutions.java 0000664 0000000 0000000 00000002171 13615100441 0027046 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2018 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import javax.management.ObjectInstance;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
final class Substitutions {
@TargetClass(EnhancedQueueExecutor.MBeanRegisterAction.class)
static final class Target_EnhancedQueueExecutor_MBeanRegisterAction {
@Substitute
public ObjectInstance run() {
return null;
}
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/ThreadLocalResettingRunnable.java 0000664 0000000 0000000 00000003675 13615100441 0031717 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2018 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
final class ThreadLocalResettingRunnable extends DelegatingRunnable {
ThreadLocalResettingRunnable(final Runnable delegate) {
super(delegate);
}
public void run() {
try {
super.run();
} finally {
Resetter.run();
}
}
public String toString() {
return "Thread-local resetting Runnable";
}
static final class Resetter {
private static final long threadLocalMapOffs;
private static final long inheritableThreadLocalMapOffs;
static {
try {
threadLocalMapOffs = JBossExecutors.unsafe.objectFieldOffset(Thread.class.getDeclaredField("threadLocals"));
inheritableThreadLocalMapOffs = JBossExecutors.unsafe.objectFieldOffset(Thread.class.getDeclaredField("inheritableThreadLocals"));
} catch (NoSuchFieldException e) {
throw new NoSuchFieldError(e.getMessage());
}
}
static void run() {
final Thread thread = Thread.currentThread();
JBossExecutors.unsafe.putObject(thread, threadLocalMapOffs, null);
JBossExecutors.unsafe.putObject(thread, inheritableThreadLocalMapOffs, null);
}
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/ThreadNameInfo.java 0000664 0000000 0000000 00000007226 13615100441 0027001 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
/**
* Thread name information.
*/
final class ThreadNameInfo {
private final long globalThreadSequenceNum;
private final long perFactoryThreadSequenceNum;
private final long factorySequenceNum;
ThreadNameInfo(final long globalThreadSequenceNum, final long perFactoryThreadSequenceNum, final long factorySequenceNum) {
this.globalThreadSequenceNum = globalThreadSequenceNum;
this.perFactoryThreadSequenceNum = perFactoryThreadSequenceNum;
this.factorySequenceNum = factorySequenceNum;
}
public long getGlobalThreadSequenceNum() {
return globalThreadSequenceNum;
}
public long getPerFactoryThreadSequenceNum() {
return perFactoryThreadSequenceNum;
}
public long getFactorySequenceNum() {
return factorySequenceNum;
}
private static final Pattern searchPattern = Pattern.compile("([^%]+)|%.");
/**
* Format the thread name string.
*
* - {@code %%} - emit a percent sign
* - {@code %t} - emit the per-factory thread sequence number
* - {@code %g} - emit the global thread sequence number
* - {@code %f} - emit the factory sequence number
* - {@code %p} - emit the {@code ":"}-separated thread group path
* - {@code %i} - emit the thread ID
* - {@code %G} - emit the thread group name
*
*
* @param thread the thread
* @param formatString the format string
* @return the thread name string
*/
public String format(Thread thread, String formatString) {
final StringBuilder builder = new StringBuilder(formatString.length() * 5);
final ThreadGroup group = thread.getThreadGroup();
final Matcher matcher = searchPattern.matcher(formatString);
while (matcher.find()) {
if (matcher.group(1) != null) {
builder.append(matcher.group());
} else {
switch (matcher.group().charAt(1)) {
case '%': builder.append('%'); break;
case 't': builder.append(perFactoryThreadSequenceNum); break;
case 'g': builder.append(globalThreadSequenceNum); break;
case 'f': builder.append(factorySequenceNum); break;
case 'p': if (group != null) appendGroupPath(group, builder); break;
case 'i': builder.append(thread.getId()); break;
case 'G': if (group != null) builder.append(group.getName()); break;
}
}
}
return builder.toString();
}
private static void appendGroupPath(ThreadGroup group, StringBuilder builder) {
final ThreadGroup parent = group.getParent();
if (parent != null) {
appendGroupPath(parent, builder);
builder.append(':');
}
builder.append(group.getName());
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/TimeUtil.java 0000664 0000000 0000000 00000002263 13615100441 0025705 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2018 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import static java.lang.Math.max;
import java.time.Duration;
/**
*/
final class TimeUtil {
private TimeUtil() {}
private static final long LARGEST_SECONDS = 9_223_372_035L; // Long.MAX_VALUE / 1_000_000_000L - 1
static long clampedPositiveNanos(Duration duration) {
final long seconds = max(0L, duration.getSeconds());
return seconds > LARGEST_SECONDS ? Long.MAX_VALUE : max(1, seconds * 1_000_000_000L + duration.getNano());
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/Version.java 0000664 0000000 0000000 00000004623 13615100441 0025600 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
/**
*
*/
public final class Version {
private Version() {
}
private static final String JAR_NAME;
private static final String VERSION_STRING;
static {
Properties versionProps = new Properties();
String jarName = "(unknown)";
String versionString = "(unknown)";
try (InputStream stream = Version.class.getResourceAsStream("Version.properties")) {
if (stream != null) try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
versionProps.load(reader);
jarName = versionProps.getProperty("jarName", jarName);
versionString = versionProps.getProperty("version", versionString);
}
} catch (IOException ignored) {
}
JAR_NAME = jarName;
VERSION_STRING = versionString;
try {
Messages.msg.version(versionString);
} catch (Throwable ignored) {}
}
/**
* Get the name of the JBoss Modules JAR.
*
* @return the name
*/
public static String getJarName() {
return JAR_NAME;
}
/**
* Get the version string of JBoss Modules.
*
* @return the version string
*/
public static String getVersionString() {
return VERSION_STRING;
}
/**
* Print out the current version on {@code System.out}.
*
* @param args ignored
*/
public static void main(String[] args) {
System.out.printf("JBoss Threads version %s\n", VERSION_STRING);
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/Version.properties 0000664 0000000 0000000 00000001353 13615100441 0027050 0 ustar 00root root 0000000 0000000 #
# JBoss, Home of Professional Open Source.
# Copyright 2017 Red Hat, Inc., and individual contributors
# as indicated by the @author tags.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
version=${project.version}
jarName=${project.artifactId}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/ViewExecutor.java 0000664 0000000 0000000 00000030103 13615100441 0026574 0 ustar 00root root 0000000 0000000 package org.jboss.threads;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import org.jboss.logging.Logger;
import org.wildfly.common.Assert;
import org.wildfly.common.lock.ExtendedLock;
import org.wildfly.common.lock.Locks;
/**
* An executor service that is actually a "view" over another executor service.
*/
public final class ViewExecutor extends AbstractExecutorService {
private static final Logger log = Logger.getLogger("org.jboss.threads.view-executor");
private static final Runnable[] NO_RUNNABLES = new Runnable[0];
private final Executor delegate;
private final ExtendedLock lock;
private final Condition shutDownCondition;
private final ArrayDeque queue;
private final Set allWrappers = Collections.newSetFromMap(new ConcurrentHashMap<>());
private int queueLimit;
private short submittedCount;
private short maxCount;
private short runningCount;
private int state = ST_RUNNING;
private volatile Thread.UncaughtExceptionHandler handler;
private volatile Runnable terminationTask;
private static final int ST_RUNNING = 0;
private static final int ST_SHUTDOWN_REQ = 1;
private static final int ST_SHUTDOWN_INT_REQ = 2;
private static final int ST_STOPPED = 3;
private ViewExecutor(final Builder builder) {
delegate = builder.getDelegate();
maxCount = (short) builder.getMaxSize();
final int queueLimit = builder.getQueueLimit();
this.queueLimit = queueLimit;
handler = builder.getUncaughtHandler();
queue = new ArrayDeque<>(Math.min(queueLimit, builder.getQueueInitialSize()));
lock = Locks.reentrantLock();
shutDownCondition = lock.newCondition();
}
public void execute(final Runnable command) {
lock.lock();
try {
if (state != ST_RUNNING) {
throw new RejectedExecutionException("Executor has been shut down");
}
final short submittedCount = this.submittedCount;
if (runningCount + submittedCount < maxCount) {
this.submittedCount = (short) (submittedCount + 1);
final TaskWrapper tw = new TaskWrapper(JBossExecutors.classLoaderPreservingTask(command));
allWrappers.add(tw);
try {
/* this cannot be easily moved outside of the lock, otherwise queued tasks might never run
* under certain rare scenarios.
*/
delegate.execute(tw);
} catch (Throwable t) {
this.submittedCount--;
allWrappers.remove(tw);
throw t;
}
} else if (queue.size() < queueLimit) {
queue.add(command);
} else {
throw new RejectedExecutionException("No executor queue space remaining");
}
} finally {
lock.unlock();
}
}
public void shutdown() {
shutdown(false);
}
public void shutdown(boolean interrupt) {
lock.lock();
int oldState = this.state;
if (oldState < ST_SHUTDOWN_REQ) {
// do shutdown
final boolean emptyQueue;
try {
emptyQueue = queue.isEmpty();
} catch (Throwable t) {
lock.unlock();
throw t;
}
if (runningCount == 0 && submittedCount == 0 && emptyQueue) {
this.state = ST_STOPPED;
try {
shutDownCondition.signalAll();
} finally {
lock.unlock();
}
runTermination();
return;
}
}
// didn't exit
this.state = interrupt ? ST_SHUTDOWN_INT_REQ : ST_SHUTDOWN_REQ;
lock.unlock();
if (interrupt && oldState < ST_SHUTDOWN_INT_REQ) {
// interrupt all runners
for (TaskWrapper wrapper : allWrappers) {
wrapper.interrupt();
}
}
}
public List shutdownNow() {
lock.lock();
int oldState = this.state;
final Runnable[] tasks;
try {
tasks = queue.toArray(NO_RUNNABLES);
queue.clear();
} catch (Throwable t) {
lock.unlock();
throw t;
}
if (oldState < ST_SHUTDOWN_INT_REQ) {
// do shutdown
if (runningCount == 0 && submittedCount == 0) {
this.state = ST_STOPPED;
try {
shutDownCondition.signalAll();
} finally {
lock.unlock();
}
runTermination();
} else {
lock.unlock();
this.state = ST_SHUTDOWN_INT_REQ;
// interrupt all runners
for (TaskWrapper wrapper : allWrappers) {
wrapper.interrupt();
}
}
} else {
lock.unlock();
}
return Arrays.asList(tasks);
}
public boolean isShutdown() {
lock.lock();
try {
return state >= ST_SHUTDOWN_REQ;
} finally {
lock.unlock();
}
}
public boolean isTerminated() {
lock.lock();
try {
return state == ST_STOPPED;
} finally {
lock.unlock();
}
}
public boolean awaitTermination(final long timeout, final TimeUnit unit) throws InterruptedException {
lock.lock();
try {
if (state == ST_STOPPED) {
return true;
}
final long nanos = unit.toNanos(timeout);
if (nanos <= 0) {
return false;
}
long elapsed = 0;
final long start = System.nanoTime();
for (;;) {
shutDownCondition.awaitNanos(nanos - elapsed);
if (state == ST_STOPPED) {
return true;
}
elapsed = System.nanoTime() - start;
if (elapsed >= nanos) {
return false;
}
}
} finally {
lock.unlock();
}
}
public Thread.UncaughtExceptionHandler getExceptionHandler() {
return handler;
}
public void setExceptionHandler(final Thread.UncaughtExceptionHandler handler) {
Assert.checkNotNullParam("handler", handler);
this.handler = handler;
}
public Runnable getTerminationTask() {
return terminationTask;
}
public void setTerminationTask(final Runnable terminationTask) {
this.terminationTask = terminationTask;
}
public String toString() {
return "view of " + delegate;
}
public static Builder builder(Executor delegate) {
Assert.checkNotNullParam("delegate", delegate);
return new Builder(delegate);
}
public static final class Builder {
private final Executor delegate;
private short maxSize = 1;
private int queueLimit = Integer.MAX_VALUE;
private int queueInitialSize = 256;
private Thread.UncaughtExceptionHandler handler = JBossExecutors.loggingExceptionHandler();
Builder(final Executor delegate) {
this.delegate = delegate;
}
public int getMaxSize() {
return maxSize;
}
public Builder setMaxSize(final int maxSize) {
Assert.checkMinimumParameter("maxSize", 1, maxSize);
Assert.checkMaximumParameter("maxSize", Short.MAX_VALUE, maxSize);
this.maxSize = (short) maxSize;
return this;
}
public int getQueueLimit() {
return queueLimit;
}
public Builder setQueueLimit(final int queueLimit) {
Assert.checkMinimumParameter("queueLimit", 0, queueLimit);
this.queueLimit = queueLimit;
return this;
}
public Executor getDelegate() {
return delegate;
}
public Thread.UncaughtExceptionHandler getUncaughtHandler() {
return handler;
}
public Builder setUncaughtHandler(final Thread.UncaughtExceptionHandler handler) {
this.handler = handler;
return this;
}
public int getQueueInitialSize() {
return queueInitialSize;
}
public Builder setQueueInitialSize(final int queueInitialSize) {
this.queueInitialSize = queueInitialSize;
return this;
}
public ViewExecutor build() {
return new ViewExecutor(this);
}
}
class TaskWrapper implements Runnable {
private volatile Thread thread;
private Runnable command;
TaskWrapper(final Runnable command) {
this.command = command;
}
void interrupt() {
final Thread thread = this.thread;
if (thread != null) {
thread.interrupt();
}
}
public void run() {
thread = Thread.currentThread();
try {
for (;;) {
lock.lock();
try {
submittedCount--;
runningCount++;
} finally {
lock.unlock();
}
try {
command.run();
} catch (Throwable t) {
try {
handler.uncaughtException(Thread.currentThread(), t);
} catch (Throwable ignored) {
}
}
lock.lock();
runningCount--;
try {
command = queue.pollFirst();
} catch (Throwable t) {
lock.unlock();
throw t;
}
if (runningCount + submittedCount < maxCount && command != null) {
// execute next
submittedCount++;
lock.unlock();
} else if (command == null && runningCount == 0 && submittedCount == 0 && state != ST_RUNNING) {
// we're the last task
state = ST_STOPPED;
try {
shutDownCondition.signalAll();
} finally {
lock.unlock();
}
runTermination();
return;
} else {
lock.unlock();
return;
}
try {
delegate.execute(this);
// resubmitted this task for execution, so return
return;
} catch (Throwable t) {
log.warn("Failed to resubmit executor task to delegate executor"
+ " (executing task immediately instead)", t);
// resubmit failed, so continue execution in this thread
}
}
} finally {
thread = null;
}
}
}
private void runTermination() {
final Runnable task = ViewExecutor.this.terminationTask;
ViewExecutor.this.terminationTask = null;
if (task != null) try {
task.run();
} catch (Throwable t) {
try {
handler.uncaughtException(Thread.currentThread(), t);
} catch (Throwable ignored) {
}
}
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/Waiter.java 0000664 0000000 0000000 00000002253 13615100441 0025403 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2018 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
/**
*/
final class Waiter {
private volatile Thread thread;
private Waiter next;
Waiter(final Waiter next) {
this.next = next;
}
Thread getThread() {
return thread;
}
Waiter setThread(final Thread thread) {
this.thread = thread;
return this;
}
Waiter getNext() {
return next;
}
Waiter setNext(final Waiter next) {
this.next = next;
return this;
}
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/management/ 0000775 0000000 0000000 00000000000 13615100441 0025417 5 ustar 00root root 0000000 0000000 ManageableThreadPoolExecutorService.java 0000664 0000000 0000000 00000002540 13615100441 0035242 0 ustar 00root root 0000000 0000000 jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/management /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads.management;
import java.util.concurrent.ExecutorService;
import org.wildfly.common.annotation.NotNull;
/**
* A thread pool for which an MBean can be obtained.
*/
public interface ManageableThreadPoolExecutorService extends ExecutorService {
/**
* Create or acquire an MXBean instance for this thread pool. Note that the thread pool itself will not
* do anything in particular to register (or unregister) the MXBean with a JMX server; that is the caller's
* responsibility.
*
* @return the MXBean instance (must not be {@code null})
*/
@NotNull
StandardThreadPoolMXBean getThreadPoolMXBean();
}
jboss-threads-3.0.1.Final/src/main/java/org/jboss/threads/management/StandardThreadPoolMXBean.java 0000664 0000000 0000000 00000024164 13615100441 0033046 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads.management;
/**
* An MXBean which contains the attributes and operations found on all standard thread pools.
*/
public interface StandardThreadPoolMXBean {
/**
* Get the pool size growth resistance factor. If the thread pool does not support growth resistance,
* then {@code 0.0} (no resistance) is returned.
*
* @return the growth resistance factor ({@code 0.0 ≤ n ≤ 1.0})
*/
float getGrowthResistance();
/**
* Set the pool size growth resistance factor, if supported.
*
* @param value the growth resistance factor ({@code 0.0 ≤ n ≤ 1.0})
*/
void setGrowthResistance(float value);
/**
* Determine whether the thread pool supports a growth resistance factor.
*
* @return {@code true} if the growth resistance factor is supported, {@code false} otherwise
*/
boolean isGrowthResistanceSupported();
/**
* Get the core pool size. This is the size below which new threads will always be created if no idle threads
* are available. If the thread pool does not support a separate core pool size, this size will match the
* maximum size.
*
* @return the core pool size
*/
int getCorePoolSize();
/**
* Set the core pool size. If the configured maximum pool size is less than the configured core size, the
* core size will be reduced to match the maximum size when the thread pool is constructed. If the thread pool
* does not support a separate core pool size, this setting will be ignored.
*
* @param corePoolSize the core pool size (must be greater than or equal to 0)
*/
void setCorePoolSize(int corePoolSize);
/**
* Determine whether this implementation supports a separate core pool size.
*
* @return {@code true} if a separate core size is supported; {@code false} otherwise
*/
boolean isCorePoolSizeSupported();
/**
* Attempt to start a core thread without submitting work to it.
*
* @return {@code true} if the thread was started, or {@code false} if the pool is filled to the core size, the
* thread could not be created, or prestart of core threads is not supported.
*/
boolean prestartCoreThread();
/**
* Attempt to start all core threads. This is usually equivalent to calling {@link #prestartCoreThread()} in a loop
* until it returns {@code false} and counting the {@code true} results.
*
* @return the number of started core threads (may be 0)
*/
int prestartAllCoreThreads();
/**
* Determine whether this thread pool allows manual pre-start of core threads.
*
* @return {@code true} if pre-starting core threads is supported, {@code false} otherwise
*/
boolean isCoreThreadPrestartSupported();
/**
* Get the maximum pool size. This is the absolute upper limit to the size of the thread pool.
*
* @return the maximum pool size
*/
int getMaximumPoolSize();
/**
* Set the maximum pool size. If the configured maximum pool size is less than the configured core size, the
* core size will be reduced to match the maximum size when the thread pool is constructed.
*
* @param maxPoolSize the maximum pool size (must be greater than or equal to 0)
*/
void setMaximumPoolSize(final int maxPoolSize);
/**
* Get an estimate of the current number of active threads in the pool.
*
* @return an estimate of the current number of active threads in the pool
*/
int getPoolSize();
/**
* Get an estimate of the peak number of threads that the pool has ever held.
*
* @return an estimate of the peak number of threads that the pool has ever held
*/
int getLargestPoolSize();
/**
* Get an estimate of the current number of active (busy) threads.
*
* @return an estimate of the active count
*/
int getActiveCount();
/**
* Determine whether core threads are allowed to time out. A "core thread" is defined as any thread in the pool
* when the pool size is below the pool's {@linkplain #getCorePoolSize() core pool size}. If the thread pool
* does not support a separate core pool size, this method should return {@code false}.
*
* This method is named differently from the typical {@code allowsCoreThreadTimeOut()} in order to accommodate
* the requirements of MXBean attribute methods.
*
* @return {@code true} if core threads are allowed to time out, {@code false} otherwise
*/
boolean isAllowCoreThreadTimeOut();
/**
* Establish whether core threads are allowed to time out. A "core thread" is defined as any thread in the pool
* when the pool size is below the pool's {@linkplain #getCorePoolSize() core pool size}. If the thread pool
* does not support a separate core pool size, the value is ignored.
*
* This method is named differently from the typical {@code allowCoreThreadTimeOut(boolean)} in order to accommodate
* the requirements of MXBean attribute methods.
*
* @param value {@code true} if core threads are allowed to time out, {@code false} otherwise
*/
void setAllowCoreThreadTimeOut(boolean value);
/**
* Get the thread keep-alive time, in seconds.
*
* This method differs from the typical {@code getKeepAliveTime(TimeUnit)} due to the inability to send in a
* time units parameter on an MXBean attribute. As such, the unit is hard-coded to seconds.
*
* @return the thread keep-alive time, in seconds
*/
long getKeepAliveTimeSeconds();
/**
* Set the thread keep-alive time, in seconds.
*
* This method differs from the typical {@code getKeepAliveTime(TimeUnit)} due to the inability to send in a
* time units parameter on an MXBean attribute. As such, the unit is hard-coded to seconds.
*
* @param seconds the thread keep-alive time, in seconds (must be greater than or equal to 0)
*/
void setKeepAliveTimeSeconds(long seconds);
/**
* Get the maximum queue size for this thread pool. If there is no queue or it is not bounded, {@link Integer#MAX_VALUE} is
* returned.
*
* @return the maximum queue size
*/
int getMaximumQueueSize();
/**
* Set the maximum queue size for this thread pool. If the new maximum queue size is smaller than the current queue
* size, there is no effect other than preventing tasks from being enqueued until the size decreases below the
* maximum again. If changing the maximum queue size is not supported, or there is no bounded backing queue,
* then the value is ignored.
*
* @param size the maximum queue size for this thread pool
*/
void setMaximumQueueSize(int size);
/**
* Get an estimate of the current queue size, if any. If no backing queue exists, or its size cannot be determined,
* this method will return 0.
*
* @return an estimate of the current queue size
*/
int getQueueSize();
/**
* Get an estimate of the peak size of the queue, if any. If no backing queue exists, or its size cannot be determined,
* this method will return 0.
*
* @return an estimate of the peak size of the queue
*/
int getLargestQueueSize();
/**
* Determine whether there is a bounded queue backing this thread pool.
*
* @return {@code true} if there is a bounded backing queue, {@code false} otherwise
*/
boolean isQueueBounded();
/**
* Determine whether the maximum queue size is modifiable.
*
* @return {@code true} if the queue size is modifiable, false otherwise
*/
boolean isQueueSizeModifiable();
/**
* Determine whether shutdown was requested.
*
* @return {@code true} if shutdown was requested, {@code false} otherwise
*/
boolean isShutdown();
/**
* Determine whether shutdown is in progress.
*
* @return {@code true} if shutdown is in progress, {@code false} otherwise
*/
boolean isTerminating();
/**
* Determine whether shutdown is complete.
*
* @return {@code true} if shutdown is complete, {@code false} otherwise
*/
boolean isTerminated();
/**
* Get an estimate of the total number of tasks ever submitted to this thread pool. This number may be zero
* if the underlying thread pool does not support this metric.
*
* @return an estimate of the total number of tasks ever submitted to this thread pool
*/
long getSubmittedTaskCount();
/**
* Get an estimate of the total number of tasks ever rejected by this thread pool for any reason. This number may be zero
* if the underlying thread pool does not support this metric.
*
* @return an estimate of the total number of tasks ever rejected by this thread pool
*/
long getRejectedTaskCount();
/**
* Get an estimate of the number of tasks completed by this thread pool. This number may be zero
* if the underlying thread pool does not support this metric.
*
* @return an estimate of the number of tasks completed by this thread pool
*/
long getCompletedTaskCount();
/**
* Get the number of spin misses that have occurred. Spin misses indicate that contention is not being properly
* handled by the thread pool.
*
* @return an estimate of the number of spin misses
*/
default long getSpinMissCount() {
return 0;
}
}
jboss-threads-3.0.1.Final/src/main/java9/ 0000775 0000000 0000000 00000000000 13615100441 0020033 5 ustar 00root root 0000000 0000000 jboss-threads-3.0.1.Final/src/main/java9/org/ 0000775 0000000 0000000 00000000000 13615100441 0020622 5 ustar 00root root 0000000 0000000 jboss-threads-3.0.1.Final/src/main/java9/org/jboss/ 0000775 0000000 0000000 00000000000 13615100441 0021742 5 ustar 00root root 0000000 0000000 jboss-threads-3.0.1.Final/src/main/java9/org/jboss/threads/ 0000775 0000000 0000000 00000000000 13615100441 0023374 5 ustar 00root root 0000000 0000000 jboss-threads-3.0.1.Final/src/main/java9/org/jboss/threads/JDKSpecific.java 0000664 0000000 0000000 00000001704 13615100441 0026317 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2018 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.time.temporal.TemporalUnit;
import java.util.concurrent.TimeUnit;
/**
*/
final class JDKSpecific {
static TemporalUnit timeToTemporal(final TimeUnit timeUnit) {
return timeUnit.toChronoUnit();
}
}
jboss-threads-3.0.1.Final/src/test/ 0000775 0000000 0000000 00000000000 13615100441 0017054 5 ustar 00root root 0000000 0000000 jboss-threads-3.0.1.Final/src/test/java/ 0000775 0000000 0000000 00000000000 13615100441 0017775 5 ustar 00root root 0000000 0000000 jboss-threads-3.0.1.Final/src/test/java/org/ 0000775 0000000 0000000 00000000000 13615100441 0020564 5 ustar 00root root 0000000 0000000 jboss-threads-3.0.1.Final/src/test/java/org/jboss/ 0000775 0000000 0000000 00000000000 13615100441 0021704 5 ustar 00root root 0000000 0000000 jboss-threads-3.0.1.Final/src/test/java/org/jboss/threads/ 0000775 0000000 0000000 00000000000 13615100441 0023336 5 ustar 00root root 0000000 0000000 jboss-threads-3.0.1.Final/src/test/java/org/jboss/threads/DeferredInterruptTestCase.java 0000664 0000000 0000000 00000004462 13615100441 0031300 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;
import junit.framework.TestCase;
/**
* @author David M. Lloyd
*/
public class DeferredInterruptTestCase extends TestCase {
public void testDeferral() throws Exception {
final AtomicBoolean delivered0 = new AtomicBoolean();
final AtomicBoolean deferred = new AtomicBoolean();
final AtomicBoolean delivered = new AtomicBoolean();
final CountDownLatch latch1 = new CountDownLatch(1);
final CountDownLatch latch2 = new CountDownLatch(1);
final JBossThread thread = new JBossThread(new Runnable() {
public void run() {
Thread.interrupted();
latch1.countDown();
LockSupport.parkNanos(3000000000L);
delivered0.set(Thread.interrupted());
JBossThread.executeWithInterruptDeferred(new Runnable() {
public void run() {
latch2.countDown();
LockSupport.parkNanos(500000000L);
deferred.set(! Thread.interrupted());
}
});
delivered.set(Thread.interrupted());
}
});
thread.start();
latch1.await();
thread.interrupt();
latch2.await();
thread.interrupt();
thread.join();
assertTrue(delivered0.get());
assertTrue(deferred.get());
assertTrue(delivered.get());
}
}
jboss-threads-3.0.1.Final/src/test/java/org/jboss/threads/EnhancedQueueExecutorTest.java 0000664 0000000 0000000 00000017050 13615100441 0031275 0 ustar 00root root 0000000 0000000 package org.jboss.threads;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import junit.framework.TestCase;
import org.junit.Ignore;
import org.junit.Test;
public class EnhancedQueueExecutorTest {
private int coreSize = 3;
private int maxSize = coreSize * 2;
private long keepaliveTimeMillis = 1000;
class TestTask implements Runnable {
private long sleepTime = 0;
public TestTask withSleepTime(long sleepTime) {
if (sleepTime > 0) {
this.sleepTime = sleepTime;
}
return this;
}
@Override
public void run() {
try {
if (sleepTime > 0) {
Thread.sleep(sleepTime);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* Test that unused threads are being reused. Scenario:
*
* - max threads = 2x, core threads = x
* - schedule x tasks, wait for tasks to finish
* - schedule x tasks, expect pool size = x immediately after
*
*/
@Test
@Ignore("https://issues.jboss.org/browse/JBTHR-67")
public void testThreadReuse() throws TimeoutException, InterruptedException {
EnhancedQueueExecutor executor = (new EnhancedQueueExecutor.Builder())
.setKeepAliveTime(keepaliveTimeMillis, TimeUnit.MILLISECONDS)
.setCorePoolSize(coreSize)
.setMaximumPoolSize(maxSize)
.build();
for (int i = 0; i < coreSize; i++) {
executor.execute(new TestTask().withSleepTime(100));
}
assertEquals("expected: == " + coreSize + ", actual: " + executor.getPoolSize(), executor.getPoolSize(), coreSize);
waitForActiveCount(executor, 0, 1000);
assertEquals("expected: == " + coreSize + ", actual: " + executor.getPoolSize(), executor.getPoolSize(), coreSize);
for (int i = 0; i < coreSize; i++) {
executor.execute(new TestTask().withSleepTime(1000));
}
assertEquals("expected: == " + coreSize + ", actual: " + executor.getPoolSize(), executor.getPoolSize(), coreSize);
executor.shutdown();
}
/**
* Test that keepalive time is honored and threads above the core count are being removed when no tasks are
* available.
*
* @throws InterruptedException
* @throws TimeoutException
*/
@Test
@Ignore("https://issues.jboss.org/browse/JBTHR-67")
public void testKeepaliveTime() throws TimeoutException, InterruptedException {
EnhancedQueueExecutor executor = (new EnhancedQueueExecutor.Builder())
.setKeepAliveTime(keepaliveTimeMillis, TimeUnit.MILLISECONDS)
.setCorePoolSize(coreSize)
.setMaximumPoolSize(maxSize)
.build();
assertTrue("expected: <=" + coreSize + ", actual: " + executor.getPoolSize(), executor.getPoolSize() <= coreSize);
for (int i = 0; i < maxSize; i++) {
executor.execute(new TestTask().withSleepTime(1000));
}
assertEquals("expected: ==" + maxSize + ", actual: " + executor.getPoolSize(), executor.getPoolSize(), maxSize);
waitForActiveCount(executor, 0, 5000);
waitForPoolSize(executor, coreSize, keepaliveTimeMillis * 2);
executor.shutdown();
}
/**
* Test that max size setting is honored. Test that keepalive time is ignored when core threads are the same as max
* threads and core thread time out is disabled.
*/
@Test
@Ignore("https://issues.jboss.org/browse/JBTHR-67")
public void testKeepaliveTime2() throws TimeoutException, InterruptedException {
EnhancedQueueExecutor executor = (new EnhancedQueueExecutor.Builder())
.setKeepAliveTime(keepaliveTimeMillis, TimeUnit.MILLISECONDS)
.setCorePoolSize(coreSize)
.setMaximumPoolSize(coreSize)
.build();
for (int i = 0; i < 2*coreSize; i++) {
executor.execute(new TestTask().withSleepTime(100));
}
int currentThreads = executor.getPoolSize();
assertEquals("expected: == " + coreSize + ", actual: " + currentThreads, currentThreads, coreSize);
waitForActiveCount(executor, 0, 5000);
assertEquals("expected: == " + currentThreads + ", actual: " + executor.getPoolSize(), executor.getPoolSize(), currentThreads);
executor.shutdown();
}
/**
* Test the keepalive setting with core thread time out enabled.
*/
@Test
@Ignore("https://issues.jboss.org/browse/JBTHR-67")
public void testKeepaliveTime3() throws TimeoutException, InterruptedException {
EnhancedQueueExecutor executor = (new EnhancedQueueExecutor.Builder())
.setKeepAliveTime(keepaliveTimeMillis, TimeUnit.MILLISECONDS)
.allowCoreThreadTimeOut(true)
.setCorePoolSize(coreSize)
.setMaximumPoolSize(maxSize)
.build();
for (int i = 0; i < maxSize; i++) {
executor.execute(new TestTask().withSleepTime(0));
}
waitForActiveCount(executor, 0, 5000);
waitForPoolSize(executor, 0, keepaliveTimeMillis * 2);
executor.shutdown();
}
/**
* Tests that prestarting core threads starts exactly the core threads amount specified.
*/
@Test
public void testPrestartCoreThreads() {
EnhancedQueueExecutor executor = (new EnhancedQueueExecutor.Builder())
.setKeepAliveTime(keepaliveTimeMillis, TimeUnit.MILLISECONDS)
.setCorePoolSize(coreSize)
.setMaximumPoolSize(maxSize)
.build();
int prestarted = executor.prestartAllCoreThreads();
assertEquals("expected: == " + coreSize + ", actual: " + prestarted, prestarted, coreSize);
assertEquals("expected: == " + coreSize + ", actual: " + executor.getPoolSize(), executor.getPoolSize(), coreSize);
executor.shutdown();
}
private void waitForPoolSize(EnhancedQueueExecutor executor, int expectedPoolSize, long waitMillis) throws TimeoutException, InterruptedException {
long deadline = System.currentTimeMillis() + waitMillis;
long delayMillis = 100;
do {
if (executor.getPoolSize() == expectedPoolSize) {
break;
}
Thread.sleep(delayMillis);
} while (System.currentTimeMillis() + delayMillis < deadline);
if (executor.getPoolSize() != expectedPoolSize) {
throw new TimeoutException("Timed out waiting for pool size to become " + expectedPoolSize
+ ", current pool size is " + executor.getPoolSize());
}
}
private void waitForActiveCount(EnhancedQueueExecutor executor, int expectedActiveCount, long waitMillis) throws TimeoutException, InterruptedException {
long deadline = System.currentTimeMillis() + waitMillis;
long delayMillis = 100;
do {
if (executor.getActiveCount() == expectedActiveCount) {
break;
}
Thread.sleep(delayMillis);
} while (System.currentTimeMillis() + delayMillis < deadline);
if (executor.getActiveCount() != expectedActiveCount) {
throw new TimeoutException("Timed out waiting for active count to become " + expectedActiveCount
+ ", current active count is " + executor.getActiveCount());
}
}
}
jboss-threads-3.0.1.Final/src/test/java/org/jboss/threads/EnhancedThreadQueueExecutorTestCase.java 0000664 0000000 0000000 00000005123 13615100441 0033217 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2018 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.Assert;
import org.junit.Test;
public class EnhancedThreadQueueExecutorTestCase {
@Test
public void testEnhancedExecutorShutdownNoTasks() throws Exception {
final CountDownLatch terminateLatch = new CountDownLatch(1);
EnhancedQueueExecutor executor = new EnhancedQueueExecutor.Builder()
.setCorePoolSize(10)
.setKeepAliveTime(1, TimeUnit.NANOSECONDS)
.setTerminationTask(new Runnable() {
@Override
public void run() {
terminateLatch.countDown();
}
})
.build();
executor.shutdown();
Assert.assertTrue(terminateLatch.await(10, TimeUnit.SECONDS));
}
@Test //JBTHR-50
public void testEnhancedExecutorShutdown() throws Exception {
final CountDownLatch terminateLatch = new CountDownLatch(1);
EnhancedQueueExecutor executor = new EnhancedQueueExecutor.Builder()
.setCorePoolSize(10)
.setKeepAliveTime(1, TimeUnit.NANOSECONDS)
.setTerminationTask(new Runnable() {
@Override
public void run() {
terminateLatch.countDown();
}
})
.build();
for(int i = 0; i < 10000; ++i) {
executor.submit(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
//ignore
}
}
});
}
executor.shutdown();
Assert.assertTrue(terminateLatch.await(10, TimeUnit.SECONDS));
}
}
jboss-threads-3.0.1.Final/src/test/java/org/jboss/threads/ThreadFactoryTestCase.java 0000664 0000000 0000000 00000013457 13615100441 0030406 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import junit.framework.TestCase;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.CountDownLatch;
/**
*
*/
public final class ThreadFactoryTestCase extends TestCase {
private static final NullRunnable NULL_RUNNABLE = new NullRunnable();
private static class NullRunnable implements Runnable {
public void run() {
}
}
private static void doTestNamePattern(JBossThreadFactory threadFactory, int expectedPerFactoryId, int expectedGlobalId, int expectedFactoryId) {
final String name = threadFactory.newThread(NULL_RUNNABLE).getName();
assertTrue("Wrong thread name (" + name + ") ", name.matches("-([a-z]+:)*one:two:three-%-" + expectedPerFactoryId + "-" + expectedGlobalId + "-" + expectedFactoryId + "-"));
}
/**
* This MUST be the first test, otherwise the sequence numbers will be wrong.
*/
public void testNamePattern() {
// TODO - skip test for now since it depends on order.
if (true) return;
final JBossThreadFactory threadFactory1 = new JBossThreadFactory(new ThreadGroup(new ThreadGroup(new ThreadGroup("one"), "two"), "three"), null,
null, "-%p-%%-%t-%g-%f-", null, null);
doTestNamePattern(threadFactory1, 1, 1, 1);
doTestNamePattern(threadFactory1, 2, 2, 1);
doTestNamePattern(threadFactory1, 3, 3, 1);
final JBossThreadFactory threadFactory2 = new JBossThreadFactory(new ThreadGroup(new ThreadGroup(new ThreadGroup("one"), "two"), "three"), null,
null, "-%p-%%-%t-%g-%f-", null, null);
doTestNamePattern(threadFactory2, 1, 4, 2);
doTestNamePattern(threadFactory2, 2, 5, 2);
doTestNamePattern(threadFactory2, 3, 6, 2);
doTestNamePattern(threadFactory2, 4, 7, 2);
// back to the first factory...
doTestNamePattern(threadFactory1, 4, 8, 1);
}
public void testDaemon() {
final JBossThreadFactory threadFactory1 = new JBossThreadFactory(null, Boolean.TRUE, null, "%t", null, null);
assertTrue("Thread is not a daemon thread", threadFactory1.newThread(NULL_RUNNABLE).isDaemon());
final JBossThreadFactory threadFactory2 = new JBossThreadFactory(null, Boolean.FALSE, null, "%t", null, null);
assertFalse("Thread should not be a daemon thread", threadFactory2.newThread(NULL_RUNNABLE).isDaemon());
}
public void testInterruptHandler() throws InterruptedException {
final AtomicBoolean wasInterrupted = new AtomicBoolean();
final AtomicBoolean called = new AtomicBoolean();
final CountDownLatch latch = new CountDownLatch(1);
final JBossThreadFactory threadFactory = new JBossThreadFactory(null, null, null, null, null, null);
final Thread t = threadFactory.newThread(new Runnable() {
public void run() {
synchronized (this) {
final InterruptHandler old = JBossThread.getAndSetInterruptHandler(new InterruptHandler() {
public void handleInterrupt(final Thread thread) {
called.set(true);
}
});
Thread.interrupted();
latch.countDown();
try {
for (;;) wait();
} catch (InterruptedException e) {
wasInterrupted.set(true);
}
}
}
});
t.start();
latch.await();
t.interrupt();
t.join();
assertTrue("Was not interrupted", wasInterrupted.get());
assertTrue("Handler was not called", called.get());
}
public void testUncaughtHandler() throws InterruptedException {
final AtomicBoolean called = new AtomicBoolean();
final JBossThreadFactory factory = new JBossThreadFactory(null, null, null, null, new Thread.UncaughtExceptionHandler() {
public void uncaughtException(final Thread t, final Throwable e) {
called.set(true);
}
}, null);
final Thread t = factory.newThread(new Runnable() {
public void run() {
throw new RuntimeException("...");
}
});
t.start();
t.join();
assertTrue("Handler was not called", called.get());
}
public void testInitialPriority() {
assertEquals("Wrong initial thread priority", 1, new JBossThreadFactory(null, null, Integer.valueOf(1), null, null, null).newThread(NULL_RUNNABLE).getPriority());
assertEquals("Wrong initial thread priority", 2, new JBossThreadFactory(null, null, Integer.valueOf(2), null, null, null).newThread(NULL_RUNNABLE).getPriority());
final ThreadGroup grp = new ThreadGroup("blah");
grp.setMaxPriority(5);
assertEquals("Wrong initial thread priority", 5, new JBossThreadFactory(grp, null, Integer.valueOf(10), null, null, null).newThread(NULL_RUNNABLE).getPriority());
assertEquals("Wrong initial thread priority", 1, new JBossThreadFactory(grp, null, Integer.valueOf(1), null, null, null).newThread(NULL_RUNNABLE).getPriority());
}
}
jboss-threads-3.0.1.Final/src/test/java/org/jboss/threads/ViewExecutorTest.java 0000664 0000000 0000000 00000010461 13615100441 0027474 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.threads;
import static org.junit.Assert.*;
import java.util.ArrayDeque;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Test;
public final class ViewExecutorTest {
@Test
public void testExecution() throws InterruptedException {
final ViewExecutor ve = ViewExecutor.builder(JBossExecutors.directExecutor()).build();
assertFalse(ve.isShutdown());
assertFalse(ve.isTerminated());
AtomicBoolean ran = new AtomicBoolean();
ve.execute(new Runnable() {
public void run() {
ran.set(true);
}
});
assertTrue(ran.get());
ve.shutdown();
assertTrue(ve.isShutdown());
assertTrue(ve.awaitTermination(10L, TimeUnit.SECONDS));
assertTrue(ve.isTerminated());
}
@Test
public void testQueuedExecution() {
final ArrayDeque executedTasks = new ArrayDeque<>();
Executor testExecutor = new QueuedExecutor(executedTasks);
final ViewExecutor ve = ViewExecutor.builder(testExecutor).setMaxSize(1).build();
AtomicBoolean ran1 = new AtomicBoolean();
ve.execute(new Runnable() {
public void run() {
ran1.set(true);
}
});
assertEquals(1, executedTasks.size());
AtomicBoolean ran2 = new AtomicBoolean();
ve.execute(new Runnable() {
public void run() {
ran2.set(true);
}
});
assertEquals(1, executedTasks.size());
executedTasks.poll().run();
assertEquals(1, executedTasks.size());
assertTrue(ran1.get());
executedTasks.poll().run();
assertTrue(ran2.get());
assertEquals(0, executedTasks.size());
}
public void testInterruptedShutdown() throws InterruptedException {
ExecutorService testExecutor = Executors.newSingleThreadExecutor();
final ViewExecutor ve = ViewExecutor.builder(testExecutor).build();
AtomicBoolean intr = new AtomicBoolean();
CountDownLatch runGate = new CountDownLatch(1);
CountDownLatch finishGate = new CountDownLatch(1);
ve.execute(new Runnable() {
public void run() {
runGate.countDown();
try {
Thread.sleep(60_000L);
} catch (InterruptedException e) {
intr.set(true);
} finally {
finishGate.countDown();
}
}
});
runGate.await();
assertFalse(intr.get());
ve.shutdown(true);
finishGate.await();
assertTrue(intr.get());
testExecutor.shutdown();
assertTrue(testExecutor.awaitTermination(5L, TimeUnit.SECONDS));
}
private static class QueuedExecutor implements Executor {
private final ArrayDeque executedTasks;
public QueuedExecutor(final ArrayDeque executedTasks) {
this.executedTasks = executedTasks;
}
public void execute(final Runnable command) {
executedTasks.add(command);
}
}
}
jboss-threads-3.0.1.Final/src/test/resources/ 0000775 0000000 0000000 00000000000 13615100441 0021066 5 ustar 00root root 0000000 0000000 jboss-threads-3.0.1.Final/src/test/resources/logging.properties 0000664 0000000 0000000 00000003073 13615100441 0024635 0 ustar 00root root 0000000 0000000 #
# JBoss, Home of Professional Open Source.
# Copyright 2017 Red Hat, Inc., and individual contributors
# as indicated by the @author tags.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Additional logger names to configure (root logger is always configured)
loggers=org.jboss.threads
# Root logger configuration
logger.level=INFO
logger.handlers=CONSOLE, FILE
logger.org.jboss.threads.level=${test.level:INFO}
# Console handler configuration
handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
handler.CONSOLE.properties=autoFlush
handler.CONSOLE.level=ALL
handler.CONSOLE.autoFlush=true
handler.CONSOLE.formatter=PATTERN
# File handler configuration
handler.FILE=org.jboss.logmanager.handlers.FileHandler
handler.FILE.level=ALL
handler.FILE.properties=autoFlush,fileName
handler.FILE.autoFlush=true
handler.FILE.fileName=./target/test.log
handler.FILE.formatter=PATTERN
# Formatter pattern configuration
formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
formatter.PATTERN.properties=pattern
formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n