18 | 18 |
package org.jboss.threads;
|
19 | 19 |
|
20 | 20 |
import static java.lang.Math.max;
|
|
21 |
import static java.lang.Thread.currentThread;
|
21 | 22 |
import static java.lang.Thread.holdsLock;
|
22 | 23 |
import static java.security.AccessController.doPrivileged;
|
23 | 24 |
import static java.security.AccessController.getContext;
|
|
52 | 53 |
import org.jboss.threads.management.StandardThreadPoolMXBean;
|
53 | 54 |
import org.wildfly.common.Assert;
|
54 | 55 |
import org.wildfly.common.annotation.NotNull;
|
55 | |
import sun.misc.Contended;
|
56 | 56 |
|
57 | 57 |
/**
|
58 | 58 |
* A task-or-thread queue backed thread pool executor service. Tasks are added in a FIFO manner, and consumers in a LIFO manner.
|
|
66 | 66 |
*
|
67 | 67 |
* @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
|
68 | 68 |
*/
|
69 | |
@Contended
|
70 | 69 |
public final class EnhancedQueueExecutor extends AbstractExecutorService implements ManageableThreadPoolExecutorService {
|
71 | 70 |
static {
|
72 | 71 |
Version.getVersionString();
|
|
220 | 219 |
volatile TaskNode tail;
|
221 | 220 |
|
222 | 221 |
/**
|
|
222 |
* The linked list of threads waiting for termination of this thread pool.
|
|
223 |
*/
|
|
224 |
@SuppressWarnings("unused") // used by field updater
|
|
225 |
volatile Waiter terminationWaiters;
|
|
226 |
|
|
227 |
/**
|
223 | 228 |
* Queue size:
|
224 | 229 |
* <ul>
|
225 | 230 |
* <li>Bit 00..1F: current queue length</li>
|
|
304 | 309 |
|
305 | 310 |
private static final AtomicReferenceFieldUpdater<EnhancedQueueExecutor, TaskNode> headUpdater = AtomicReferenceFieldUpdater.newUpdater(EnhancedQueueExecutor.class, TaskNode.class, "head");
|
306 | 311 |
private static final AtomicReferenceFieldUpdater<EnhancedQueueExecutor, TaskNode> tailUpdater = AtomicReferenceFieldUpdater.newUpdater(EnhancedQueueExecutor.class, TaskNode.class, "tail");
|
|
312 |
private static final AtomicReferenceFieldUpdater<EnhancedQueueExecutor, Waiter> terminationWaitersUpdater = AtomicReferenceFieldUpdater.newUpdater(EnhancedQueueExecutor.class, Waiter.class, "terminationWaiters");
|
307 | 313 |
|
308 | 314 |
private static final AtomicLongFieldUpdater<EnhancedQueueExecutor> queueSizeUpdater = AtomicLongFieldUpdater.newUpdater(EnhancedQueueExecutor.class, "queueSize");
|
309 | 315 |
private static final AtomicLongFieldUpdater<EnhancedQueueExecutor> threadStatusUpdater = AtomicLongFieldUpdater.newUpdater(EnhancedQueueExecutor.class, "threadStatus");
|
|
342 | 348 |
// Marker objects
|
343 | 349 |
// =======================================================
|
344 | 350 |
|
|
351 |
static final QNode TERMINATE_REQUESTED = new TerminateWaiterNode(null);
|
345 | 352 |
static final QNode TERMINATE_COMPLETE = new TerminateWaiterNode(null);
|
|
353 |
|
|
354 |
static final Waiter TERMINATE_COMPLETE_WAITER = new Waiter(null);
|
346 | 355 |
|
347 | 356 |
static final Runnable WAITING = new NullRunnable();
|
348 | 357 |
static final Runnable GAVE_UP = new NullRunnable();
|
|
379 | 388 |
public ObjectInstance run() {
|
380 | 389 |
try {
|
381 | 390 |
final Hashtable<String, String> table = new Hashtable<>();
|
382 | |
table.put("name", finalName);
|
|
391 |
table.put("name", ObjectName.quote(finalName));
|
383 | 392 |
table.put("type", "thread-pool");
|
384 | 393 |
return ManagementFactory.getPlatformMBeanServer().registerMBean(mxBean, new ObjectName("jboss.threads", table));
|
385 | 394 |
} catch (Throwable ignored) {
|
|
825 | 834 |
if (runningThreads.contains(thread)) {
|
826 | 835 |
throw Messages.msg.cannotAwaitWithin();
|
827 | 836 |
}
|
828 | |
final TerminateWaiterNode node = new TerminateWaiterNode(thread);
|
829 | |
// stick it on the queue
|
830 | |
QNode tail = this.tail;
|
831 | |
QNode tailNext;
|
832 | |
for (;;) {
|
833 | |
tailNext = tail.getNext();
|
834 | |
if (tailNext == null) {
|
835 | |
if (tail.compareAndSetNext(null, node)) {
|
836 | |
// now we wait!
|
837 | |
break;
|
838 | |
}
|
839 | |
} else if (tailNext == TERMINATE_COMPLETE) {
|
840 | |
// nothing more to be done!
|
|
837 |
Waiter waiters = this.terminationWaiters;
|
|
838 |
if (waiters == TERMINATE_COMPLETE_WAITER) {
|
|
839 |
return true;
|
|
840 |
}
|
|
841 |
final Waiter waiter = new Waiter(waiters);
|
|
842 |
waiter.setThread(currentThread());
|
|
843 |
while (! compareAndSetTerminationWaiters(waiters, waiter)) {
|
|
844 |
waiters = this.terminationWaiters;
|
|
845 |
if (waiters == TERMINATE_COMPLETE_WAITER) {
|
841 | 846 |
return true;
|
842 | |
} else {
|
843 | |
if (UPDATE_TAIL && tailNext instanceof TaskNode) {
|
844 | |
assert tail instanceof TaskNode; // else tailNext couldn't possibly be a TaskNode
|
845 | |
compareAndSetTail(((TaskNode) tail), ((TaskNode) tailNext));
|
846 | |
}
|
847 | |
tail = tailNext;
|
848 | 847 |
}
|
|
848 |
waiter.setNext(waiters);
|
849 | 849 |
}
|
850 | 850 |
try {
|
851 | 851 |
parkNanos(this, unit.toNanos(timeout));
|
852 | 852 |
} finally {
|
853 | 853 |
// prevent future spurious unparks without sabotaging the queue's integrity
|
854 | |
node.getAndClearThread();
|
|
854 |
waiter.setThread(null);
|
855 | 855 |
}
|
856 | 856 |
}
|
857 | 857 |
if (Thread.interrupted()) throw new InterruptedException();
|
|
910 | 910 |
TaskNode tail = this.tail;
|
911 | 911 |
QNode tailNext;
|
912 | 912 |
// a marker to indicate that termination was requested
|
913 | |
final TerminateWaiterNode terminateNode = new TerminateWaiterNode(null);
|
914 | 913 |
for (;;) {
|
915 | 914 |
tailNext = tail.getNext();
|
916 | 915 |
if (tailNext instanceof TaskNode) {
|
|
926 | 925 |
// tail(snapshot) is a task node
|
927 | 926 |
// tail(snapshot).next is a (list of) pool thread node(s) or null
|
928 | 927 |
// postconditions (succeed):
|
929 | |
// tail(snapshot).next is terminateNode(null)
|
930 | |
if (tail.compareAndSetNext(node, terminateNode)) {
|
|
928 |
// tail(snapshot).next is TERMINATE_REQUESTED
|
|
929 |
if (tail.compareAndSetNext(node, TERMINATE_REQUESTED)) {
|
931 | 930 |
// got it!
|
932 | 931 |
// state change sh3:
|
933 | 932 |
// node.task ← EXIT
|
|
1759 | 1758 |
this.terminationTask = null;
|
1760 | 1759 |
safeRun(terminationTask);
|
1761 | 1760 |
// notify all waiters
|
1762 | |
QNode tail = EnhancedQueueExecutor.this.tail;
|
1763 | |
QNode tailNext = tail.getAndSetNext(TERMINATE_COMPLETE);
|
1764 | |
while (tailNext != null) {
|
1765 | |
// state change ct1:
|
1766 | |
// tail(snapshot).next(snapshot).thread ← null
|
1767 | |
// succeeds: sh2
|
1768 | |
// preconditions:
|
1769 | |
// threadStatus is shutdown (because sh1 ≺ … ≺ ct1)
|
1770 | |
// postconditions: -
|
1771 | |
// post-actions:
|
1772 | |
// unpark(twn)
|
1773 | |
if (tailNext instanceof TerminateWaiterNode) {
|
1774 | |
unpark(((TerminateWaiterNode) tailNext).getAndClearThread());
|
1775 | |
}
|
1776 | |
tailNext = tailNext.getNext();
|
1777 | |
}
|
|
1761 |
Waiter waiters = getAndSetTerminationWaiters(TERMINATE_COMPLETE_WAITER);
|
|
1762 |
while (waiters != null) {
|
|
1763 |
unpark(waiters.getThread());
|
|
1764 |
waiters = waiters.getNext();
|
|
1765 |
}
|
|
1766 |
tail.getAndSetNext(TERMINATE_COMPLETE);
|
1778 | 1767 |
final ObjectInstance handle = this.handle;
|
1779 | 1768 |
if (handle != null) {
|
1780 | 1769 |
doPrivileged(new PrivilegedAction<Void>() {
|
|
1825 | 1814 |
tailUpdater.compareAndSet(this, expect, update);
|
1826 | 1815 |
}
|
1827 | 1816 |
|
|
1817 |
boolean compareAndSetTerminationWaiters(final Waiter expect, final Waiter update) {
|
|
1818 |
return terminationWaitersUpdater.compareAndSet(this, expect, update);
|
|
1819 |
}
|
|
1820 |
|
|
1821 |
Waiter getAndSetTerminationWaiters(final Waiter update) {
|
|
1822 |
return terminationWaitersUpdater.getAndSet(this, update);
|
|
1823 |
}
|
|
1824 |
|
1828 | 1825 |
// =======================================================
|
1829 | 1826 |
// Queue size operations
|
1830 | 1827 |
// =======================================================
|
|
2036 | 2033 |
// Node classes
|
2037 | 2034 |
// =======================================================
|
2038 | 2035 |
|
2039 | |
@Contended
|
2040 | 2036 |
abstract static class QNode {
|
2041 | 2037 |
// in 9, use VarHandle
|
2042 | 2038 |
private static final AtomicReferenceFieldUpdater<QNode, QNode> nextUpdater = AtomicReferenceFieldUpdater.newUpdater(QNode.class, QNode.class, "next");
|
|
2061 | 2057 |
}
|
2062 | 2058 |
}
|
2063 | 2059 |
|
2064 | |
@Contended
|
2065 | 2060 |
static final class PoolThreadNode extends QNode {
|
2066 | 2061 |
private final Thread thread;
|
2067 | 2062 |
|
|
2093 | 2088 |
}
|
2094 | 2089 |
}
|
2095 | 2090 |
|
2096 | |
@Contended
|
2097 | 2091 |
static final class TerminateWaiterNode extends QNode {
|
2098 | 2092 |
private volatile Thread thread;
|
2099 | 2093 |
|
|
2117 | 2111 |
}
|
2118 | 2112 |
}
|
2119 | 2113 |
|
2120 | |
@Contended
|
2121 | 2114 |
static final class TaskNode extends QNode {
|
2122 | 2115 |
volatile Runnable task;
|
2123 | 2116 |
|