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

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

There is a newer version: 3.8.0.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2008, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt 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 java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicInteger;

import org.jboss.logging.Logger;

/**
 * A JBoss thread.  Supports logging and extra operations.
 */
public final class JBossThread extends Thread {
    private static final Logger log = Logger.getLogger("org.jboss.threads");
    private static final Logger ihlog = Logger.getLogger("org.jboss.threads.interrupt-handler");

    private volatile InterruptHandler interruptHandler;
    private ThreadNameInfo threadNameInfo;

    private final AtomicInteger intCnt = new AtomicInteger();

    /**
     * Construct a new instance.
     *
     * @param target the runnable target
     * @see #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(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(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(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(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() {
        if (Thread.currentThread() != this) checkAccess();
        // fast check
        if (isInterrupted()) return;
        final AtomicInteger intCnt = this.intCnt;
        int oldVal;
        do {
            oldVal = intCnt.get();
            if ((oldVal & 0x8000_0000) != 0) {
                // deferred interrupt already set
                ihlog.tracef("Interrupting thread \"%s\" (already deferred)", this);
                return;
            }
            if (oldVal == 0) {
                synchronized (intCnt) {
                    oldVal = intCnt.get();
                    if (oldVal == 0) {
                        doInterrupt();
                        return;
                    }
                }
            }
            assert oldVal != 0;
        } while (! intCnt.compareAndSet(oldVal, oldVal | 0x8000_0000));
        ihlog.tracef("Interrupting thread \"%s\" (deferred)", this);
    }

    private void doInterrupt() {
        assert Thread.holdsLock(intCnt);
        if (isInterrupted()) return;
        ihlog.tracef("Interrupting thread \"%s\"", this);
        try {
            super.interrupt();
        } finally {
            final InterruptHandler interruptHandler = this.interruptHandler;
            if (interruptHandler != null) {
                try {
                    interruptHandler.handleInterrupt(this);
                } catch (Throwable t) {
                    ihlog.errorf(t, "Interrupt handler %s threw an exception", interruptHandler);
                }
            }
        }
    }

    public boolean isInterrupted() {
        return this == Thread.currentThread() ? super.isInterrupted() : super.isInterrupted() || (intCnt.get() & 0x8000_0000) != 0;
    }

    /**
     * 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 (thread == null) {
            directExecutor.execute(task);
            return;
        }
        boolean intr = registerDeferral(thread);
        assert ! Thread.interrupted();
        try {
            directExecutor.execute(task);
        } finally {
            unregisterDeferral(intr, thread);
        }
    }

    /**
     * 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
     * @param T 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 (thread == null) {
            return action.call();
        }
        boolean intr = registerDeferral(thread);
        assert ! Thread.interrupted();
        try {
            return action.call();
        } finally {
            unregisterDeferral(intr, thread);
        }
    }

    /**
     * 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
     * @param T the value returned from the callable
     */
    public static  T executeWithInterruptDeferred(final PrivilegedAction action) {
        final JBossThread thread = currentThread();
        if (thread == null) {
            return action.run();
        }
        boolean intr = registerDeferral(thread);
        assert ! Thread.interrupted();
        try {
            return action.run();
        } finally {
            unregisterDeferral(intr, thread);
        }
    }

    /**
     * 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
     * @param T 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 (thread == null) {
            return action.run();
        }
        boolean intr = registerDeferral(thread);
        assert ! Thread.interrupted();
        try {
            return action.run();
        } finally {
            unregisterDeferral(intr, thread);
        }
    }

    private static void unregisterDeferral(final boolean intr, final JBossThread thread) {
        int oldVal;
        final AtomicInteger intCnt = thread.intCnt;
        do {
            oldVal = intCnt.get();
            if ((oldVal & 0x7fff_ffff) == 1) {
                synchronized (intCnt) {
                    oldVal = intCnt.get();
                    if (oldVal == 1) {
                        intCnt.set(0);
                        if (intr) {
                            thread.doInterrupt();
                            break;
                        }
                        // no interrupt occurred during the operation
                        break;
                    } else if (oldVal == 0x8000_0001) {
                        intCnt.set(0);
                        // deferral complete
                        thread.doInterrupt();
                        break;
                    }
                }
            }
            assert (oldVal & 0x7fff_ffff) > 1;
        } while (! intCnt.compareAndSet(oldVal, oldVal - 1));
    }

    private static boolean registerDeferral(final JBossThread thread) {
        boolean intr = false;
        final AtomicInteger intCnt = thread.intCnt;
        int oldVal;
        do {
            oldVal = intCnt.get();
            if (oldVal == 0) {
                synchronized (intCnt) {
                    oldVal = intCnt.get();
                    if (oldVal == 0) {
                        intCnt.set(1);
                        intr = Thread.interrupted();
                        break;
                    }
                }
            }
            if (oldVal == 0x7fff_ffff) {
                // extremely unlikely
                throw new IllegalStateException();
            }
            assert (oldVal & 0x7fff_ffff) > 0;
        } while (! intCnt.compareAndSet(oldVal, oldVal + 1));
        return intr;
    }

    /**
     * Execute the thread's {@code Runnable}.  Logs a trace message at the start and end of execution.
     */
    public void run() {
        log.tracef("Thread \"%s\" starting execution", this);
        try {
            super.run();
        } finally {
            log.tracef("Thread \"%s\" exiting", this);
        }
    }

    /**
     * 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();
        log.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);
        log.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 new IllegalStateException("The current thread does not support interrupt handlers"); } try { return thread.interruptHandler; } finally { thread.interruptHandler = newInterruptHandler; } } /** * 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 - 2025 Weber Informatics LLC | Privacy Policy