All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.threads.JBossThread Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 33.0.2.Final
Show newest version
/*
 * 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.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.cpu.ProcessorInfo;
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");
    private static final int MAX_INTERRUPT_SPINS = AccessController.doPrivileged(new PrivilegedAction() {
        public Integer run() {
            return Integer.valueOf(Integer.parseInt(System.getProperty("jboss.threads.interrupt.spins", ProcessorInfo.availableProcessors() == 1 ? "0" : "128")));
        }
    }).intValue();

    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; int spins = 0; for (;;) { oldVal = stateRef.get(); if (oldVal == STATE_INTERRUPT_PENDING) { // already set Messages.msg.tracef("Interrupting thread \"%s\" (already interrupted)", this); return; } else if (oldVal == STATE_INTERRUPT_IN_PROGRESS) { // wait for interruption on other thread to be completed if (spins < MAX_INTERRUPT_SPINS) { //JDKSpecific.onSpinWait(); spins++; } else { Thread.yield(); } continue; } else { if (oldVal == STATE_INTERRUPT_DEFERRED) { newVal = STATE_INTERRUPT_PENDING; } else { newVal = STATE_INTERRUPT_IN_PROGRESS; } } if (stateRef.compareAndSet(oldVal, newVal)) { break; } } 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) { executeWithInterruptDeferred(JBossExecutors.directExecutor(), task); } /** * 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 directExecutor the task executor to use * @param task the task to run */ public static void executeWithInterruptDeferred(final DirectExecutor directExecutor, final Runnable task) { final JBossThread thread = currentThread(); if (registerDeferral(thread)) try { directExecutor.execute(task); } finally { unregisterDeferral(thread); } else { // already deferred directExecutor.execute(task); } } /** * 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; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy