Programming for thread in Java

Override Annotation

 package java.lang;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* Annotation type used to mark methods that override a method declaration in a
* superclass. Compilers produce an error if a method annotated with @Override
* does not actually override a method in a superclass.
*
* @since 1.5
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

Runnable Interface

 package java.lang;
/**
* Represents a command that can be executed. Often used to run code in a
* different {@link Thread}.
*/
public interface Runnable {
public void run();
}

Thread Class

 package java.lang;
import dalvik.system.VMStack;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import libcore.util.EmptyArray; /**
* A {@code Thread} is a concurrent unit of execution. It has its own call stack
* for methods being invoked, their arguments and local variables. Each virtual
* machine instance has at least one main {@code Thread} running when it is
* started; typically, there are several others for housekeeping. The
* application might decide to launch additional {@code Thread}s for specific
* purposes.
* <p>
* {@code Thread}s in the same VM interact and synchronize by the use of shared
* objects and monitors associated with these objects. Synchronized methods and
* part of the API in {@link Object} also allow {@code Thread}s to cooperate.
* <p>
* There are basically two main ways of having a {@code Thread} execute
* application code. One is providing a new class that extends {@code Thread}
* and overriding its {@link #run()} method. The other is providing a new
* {@code Thread} instance with a {@link Runnable} object during its creation.
* In both cases, the {@link #start()} method must be called to actually execute
* the new {@code Thread}.
* <p>
* Each {@code Thread} has an integer priority that basically determines the
* amount of CPU time the {@code Thread} gets. It can be set using the
* {@link #setPriority(int)} method. A {@code Thread} can also be made a daemon,
* which makes it run in the background. The latter also affects VM termination
* behavior: the VM does not terminate automatically as long as there are
* non-daemon threads running.
*
* @see java.lang.Object
* @see java.lang.ThreadGroup
*
*/
public class Thread implements Runnable {
private static final int NANOS_PER_MILLI = 1000000; /** Park states */
private static class ParkState {
/** park state indicating unparked */
private static final int UNPARKED = 1;
/** park state indicating preemptively unparked */
private static final int PREEMPTIVELY_UNPARKED = 2;
/** park state indicating parked */
private static final int PARKED = 3;
}
/**
* A representation of a thread's state. A given thread may only be in one
* state at a time.
*/
public enum State {
/**
* The thread has been created, but has never been started.
*/
NEW,
/**
* The thread may be run.
*/
RUNNABLE,
/**
* The thread is blocked and waiting for a lock.
*/
BLOCKED,
/**
* The thread is waiting.
*/
WAITING,
/**
* The thread is waiting for a specified amount of time.
*/
TIMED_WAITING,
/**
* The thread has been terminated.
*/
TERMINATED
}
/**
* The maximum priority value allowed for a thread.
*/
public static final int MAX_PRIORITY = 10;
/**
* The minimum priority value allowed for a thread.
*/
public static final int MIN_PRIORITY = 1;
/**
* The normal (default) priority value assigned to threads.
*/
public static final int NORM_PRIORITY = 5;
/* some of these are accessed directly by the VM; do not rename them */
volatile VMThread vmThread;
volatile ThreadGroup group;
volatile boolean daemon;
volatile String name;
volatile int priority;
volatile long stackSize;
Runnable target;
private static int count = 0;
/**
* Holds the thread's ID. We simply count upwards, so
* each Thread has a unique ID.
*/
private long id;
/**
* Normal thread local values.
*/
ThreadLocal.Values localValues;
/**
* Inheritable thread local values.
*/
ThreadLocal.Values inheritableValues;
/** Callbacks to run on interruption. */
private final List<Runnable> interruptActions = new ArrayList<Runnable>();
/**
* Holds the class loader for this Thread, in case there is one.
*/
private ClassLoader contextClassLoader;
/**
* Holds the handler for uncaught exceptions in this Thread,
* in case there is one.
*/
private UncaughtExceptionHandler uncaughtHandler;
/**
* Holds the default handler for uncaught exceptions, in case there is one.
*/
private static UncaughtExceptionHandler defaultUncaughtHandler;
/**
* Reflects whether this Thread has already been started. A Thread
* can only be started once (no recycling). Also, we need it to deduce
* the proper Thread status.
*/
boolean hasBeenStarted = false; /** the park state of the thread */
private int parkState = ParkState.UNPARKED; /** The synchronization object responsible for this thread parking. */
private Object parkBlocker; /**
* Constructs a new {@code Thread} with no {@code Runnable} object and a
* newly generated name. The new {@code Thread} will belong to the same
* {@code ThreadGroup} as the {@code Thread} calling this constructor.
*
* @see java.lang.ThreadGroup
* @see java.lang.Runnable
*/
public Thread() {
create(null, null, null, 0);
}
/**
* Constructs a new {@code Thread} with a {@code Runnable} object and a
* newly generated name. The new {@code Thread} will belong to the same
* {@code ThreadGroup} as the {@code Thread} calling this constructor.
*
* @param runnable
* a {@code Runnable} whose method <code>run</code> will be
* executed by the new {@code Thread}
*
* @see java.lang.ThreadGroup
* @see java.lang.Runnable
*/
public Thread(Runnable runnable) {
create(null, runnable, null, 0);
} /**
* Constructs a new {@code Thread} with a {@code Runnable} object and name
* provided. The new {@code Thread} will belong to the same {@code
* ThreadGroup} as the {@code Thread} calling this constructor.
*
* @param runnable
* a {@code Runnable} whose method <code>run</code> will be
* executed by the new {@code Thread}
* @param threadName
* the name for the {@code Thread} being created
*
* @see java.lang.ThreadGroup
* @see java.lang.Runnable
*/
public Thread(Runnable runnable, String threadName) {
if (threadName == null) {
throw new NullPointerException();
} create(null, runnable, threadName, 0);
} /**
* Constructs a new {@code Thread} with no {@code Runnable} object and the
* name provided. The new {@code Thread} will belong to the same {@code
* ThreadGroup} as the {@code Thread} calling this constructor.
*
* @param threadName
* the name for the {@code Thread} being created
*
* @see java.lang.ThreadGroup
* @see java.lang.Runnable
*
*/
public Thread(String threadName) {
if (threadName == null) {
throw new NullPointerException();
} create(null, null, threadName, 0);
} /**
* Constructs a new {@code Thread} with a {@code Runnable} object and a
* newly generated name. The new {@code Thread} will belong to the {@code
* ThreadGroup} passed as parameter.
*
* @param group
* {@code ThreadGroup} to which the new {@code Thread} will
* belong
* @param runnable
* a {@code Runnable} whose method <code>run</code> will be
* executed by the new {@code Thread}
* @throws IllegalThreadStateException
* if <code>group.destroy()</code> has already been done
* @see java.lang.ThreadGroup
* @see java.lang.Runnable
*/
public Thread(ThreadGroup group, Runnable runnable) {
create(group, runnable, null, 0);
} /**
* Constructs a new {@code Thread} with a {@code Runnable} object, the given
* name and belonging to the {@code ThreadGroup} passed as parameter.
*
* @param group
* ThreadGroup to which the new {@code Thread} will belong
* @param runnable
* a {@code Runnable} whose method <code>run</code> will be
* executed by the new {@code Thread}
* @param threadName
* the name for the {@code Thread} being created
* @throws IllegalThreadStateException
* if <code>group.destroy()</code> has already been done
* @see java.lang.ThreadGroup
* @see java.lang.Runnable
*/
public Thread(ThreadGroup group, Runnable runnable, String threadName) {
if (threadName == null) {
throw new NullPointerException();
} create(group, runnable, threadName, 0);
} /**
* Constructs a new {@code Thread} with no {@code Runnable} object, the
* given name and belonging to the {@code ThreadGroup} passed as parameter.
*
* @param group
* {@code ThreadGroup} to which the new {@code Thread} will belong
* @param threadName
* the name for the {@code Thread} being created
* @throws IllegalThreadStateException
* if <code>group.destroy()</code> has already been done
* @see java.lang.ThreadGroup
* @see java.lang.Runnable
*/
public Thread(ThreadGroup group, String threadName) {
if (threadName == null) {
throw new NullPointerException();
} create(group, null, threadName, 0);
} /**
* Constructs a new {@code Thread} with a {@code Runnable} object, the given
* name and belonging to the {@code ThreadGroup} passed as parameter.
*
* @param group
* {@code ThreadGroup} to which the new {@code Thread} will
* belong
* @param runnable
* a {@code Runnable} whose method <code>run</code> will be
* executed by the new {@code Thread}
* @param threadName
* the name for the {@code Thread} being created
* @param stackSize
* a stack size for the new {@code Thread}. This has a highly
* platform-dependent interpretation. It may even be ignored
* completely.
* @throws IllegalThreadStateException
* if <code>group.destroy()</code> has already been done
* @see java.lang.ThreadGroup
* @see java.lang.Runnable
*/
public Thread(ThreadGroup group, Runnable runnable, String threadName, long stackSize) {
if (threadName == null) {
throw new NullPointerException();
}
create(group, runnable, threadName, stackSize);
} /**
* Package-scope method invoked by Dalvik VM to create "internal"
* threads or attach threads created externally.
*
* Don't call Thread.currentThread(), since there may not be such
* a thing (e.g. for Main).
*/
Thread(ThreadGroup group, String name, int priority, boolean daemon) {
synchronized (Thread.class) {
id = ++Thread.count;
} if (name == null) {
this.name = "Thread-" + id;
} else {
this.name = name;
} if (group == null) {
throw new InternalError("group not specified");
} this.group = group; this.target = null;
this.stackSize = 0;
this.priority = priority;
this.daemon = daemon; /* add ourselves to our ThreadGroup of choice */
this.group.addThread(this);
} /**
* Initializes a new, existing Thread object with a runnable object,
* the given name and belonging to the ThreadGroup passed as parameter.
* This is the method that the several public constructors delegate their
* work to.
*
* @param group ThreadGroup to which the new Thread will belong
* @param runnable a java.lang.Runnable whose method <code>run</code> will
* be executed by the new Thread
* @param threadName Name for the Thread being created
* @param stackSize Platform dependent stack size
* @throws IllegalThreadStateException if <code>group.destroy()</code> has
* already been done
* @see java.lang.ThreadGroup
* @see java.lang.Runnable
*/
private void create(ThreadGroup group, Runnable runnable, String threadName, long stackSize) {
Thread currentThread = Thread.currentThread();
if (group == null) {
group = currentThread.getThreadGroup();
} if (group.isDestroyed()) {
throw new IllegalThreadStateException("Group already destroyed");
} this.group = group; synchronized (Thread.class) {
id = ++Thread.count;
} if (threadName == null) {
this.name = "Thread-" + id;
} else {
this.name = threadName;
} this.target = runnable;
this.stackSize = stackSize; this.priority = currentThread.getPriority(); this.contextClassLoader = currentThread.contextClassLoader; // Transfer over InheritableThreadLocals.
if (currentThread.inheritableValues != null) {
inheritableValues = new ThreadLocal.Values(currentThread.inheritableValues);
} // add ourselves to our ThreadGroup of choice
this.group.addThread(this);
} /**
* Returns the number of active {@code Thread}s in the running {@code
* Thread}'s group and its subgroups.
*
* @return the number of {@code Thread}s
*/
public static int activeCount() {
return currentThread().getThreadGroup().activeCount();
} /**
* Does nothing.
*/
public final void checkAccess() {
} /**
* Returns the number of stack frames in this thread.
*
* @return Number of stack frames
* @deprecated The results of this call were never well defined. To make
* things worse, it would depend on whether the Thread was
* suspended or not, and suspend was deprecated too.
*/
@Deprecated
public int countStackFrames() {
return getStackTrace().length;
} /**
* Returns the Thread of the caller, that is, the current Thread.
*
* @return the current Thread.
*/
public static Thread currentThread() {
return VMThread.currentThread();
} /**
* Destroys the receiver without any monitor cleanup.
*
* @deprecated Not implemented.
*/
@Deprecated
public void destroy() {
throw new NoSuchMethodError("Thread.destroy()"); // TODO Externalize???
} /**
* Prints to the standard error stream a text representation of the current
* stack for this Thread.
*
* @see Throwable#printStackTrace()
*/
public static void dumpStack() {
new Throwable("stack dump").printStackTrace();
} /**
* Copies an array with all Threads which are in the same ThreadGroup as the
* receiver - and subgroups - into the array <code>threads</code> passed as
* parameter. If the array passed as parameter is too small no exception is
* thrown - the extra elements are simply not copied.
*
* @param threads
* array into which the Threads will be copied
* @return How many Threads were copied over
*/
public static int enumerate(Thread[] threads) {
Thread thread = Thread.currentThread();
return thread.getThreadGroup().enumerate(threads);
} /**
* Returns a map of all the currently live threads to their stack traces.
*/
public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
Map<Thread, StackTraceElement[]> map = new HashMap<Thread, StackTraceElement[]>(); // Find out how many live threads we have. Allocate a bit more
// space than needed, in case new ones are just being created.
int count = ThreadGroup.mSystem.activeCount();
Thread[] threads = new Thread[count + count / 2]; // Enumerate the threads and collect the stacktraces.
count = ThreadGroup.mSystem.enumerate(threads);
for (int i = 0; i < count; i++) {
map.put(threads[i], threads[i].getStackTrace());
} return map;
} /**
* Returns the context ClassLoader for this Thread.
*
* @return ClassLoader The context ClassLoader
* @see java.lang.ClassLoader
* @see #getContextClassLoader()
*/
public ClassLoader getContextClassLoader() {
return contextClassLoader;
} /**
* Returns the default exception handler that's executed when uncaught
* exception terminates a thread.
*
* @return an {@link UncaughtExceptionHandler} or <code>null</code> if
* none exists.
*/
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() {
return defaultUncaughtHandler;
} /**
* Returns the thread's identifier. The ID is a positive <code>long</code>
* generated on thread creation, is unique to the thread, and doesn't change
* during the lifetime of the thread; the ID may be reused after the thread
* has been terminated.
*
* @return the thread's ID.
*/
public long getId() {
return id;
} /**
* Returns the name of the Thread.
*
* @return the Thread's name
*/
public final String getName() {
return name;
} /**
* Returns the priority of the Thread.
*
* @return the Thread's priority
* @see Thread#setPriority
*/
public final int getPriority() {
return priority;
} /**
* Returns an array of {@link StackTraceElement} representing the current thread's stack.
*/
public StackTraceElement[] getStackTrace() {
StackTraceElement ste[] = VMStack.getThreadStackTrace(this);
return ste != null ? ste : EmptyArray.STACK_TRACE_ELEMENT;
} /**
* Returns the current state of the Thread. This method is useful for
* monitoring purposes.
*
* @return a {@link State} value.
*/
public State getState() {
// TODO This is ugly and should be implemented better.
VMThread vmt = this.vmThread; // Make sure we have a valid reference to an object. If native code
// deletes the reference we won't run into a null reference later.
VMThread thread = vmThread;
if (thread != null) {
// If the Thread Object became invalid or was not yet started,
// getStatus() will return -1.
int state = thread.getStatus();
if(state != -1) {
return VMThread.STATE_MAP[state];
}
}
return hasBeenStarted ? Thread.State.TERMINATED : Thread.State.NEW;
} /**
* Returns the ThreadGroup to which this Thread belongs.
*
* @return the Thread's ThreadGroup
*/
public final ThreadGroup getThreadGroup() {
// TODO This should actually be done at native termination.
if (getState() == Thread.State.TERMINATED) {
return null;
} else {
return group;
}
} /**
* Returns the thread's uncaught exception handler. If not explicitly set,
* then the ThreadGroup's handler is returned. If the thread is terminated,
* then <code>null</code> is returned.
*
* @return an {@link UncaughtExceptionHandler} instance or {@code null}.
*/
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
if (uncaughtHandler != null)
return uncaughtHandler;
else
return group; // ThreadGroup is instance of UEH
} /**
* Posts an interrupt request to this {@code Thread}. The behavior depends on
* the state of this {@code Thread}:
* <ul>
* <li>
* {@code Thread}s blocked in one of {@code Object}'s {@code wait()} methods
* or one of {@code Thread}'s {@code join()} or {@code sleep()} methods will
* be woken up, their interrupt status will be cleared, and they receive an
* {@link InterruptedException}.
* <li>
* {@code Thread}s blocked in an I/O operation of an
* {@link java.nio.channels.InterruptibleChannel} will have their interrupt
* status set and receive an
* {@link java.nio.channels.ClosedByInterruptException}. Also, the channel
* will be closed.
* <li>
* {@code Thread}s blocked in a {@link java.nio.channels.Selector} will have
* their interrupt status set and return immediately. They don't receive an
* exception in this case.
* <ul>
*
* @see Thread#interrupted
* @see Thread#isInterrupted
*/
public void interrupt() {
synchronized (interruptActions) {
for (int i = interruptActions.size() - 1; i >= 0; i--) {
interruptActions.get(i).run();
}
} VMThread vmt = this.vmThread;
if (vmt != null) {
vmt.interrupt();
}
} /**
* Returns a <code>boolean</code> indicating whether the current Thread (
* <code>currentThread()</code>) has a pending interrupt request (<code>
* true</code>) or not (<code>false</code>). It also has the side-effect of
* clearing the flag.
*
* @return a <code>boolean</code> indicating the interrupt status
* @see Thread#currentThread
* @see Thread#interrupt
* @see Thread#isInterrupted
*/
public static boolean interrupted() {
return VMThread.interrupted();
} /**
* Returns <code>true</code> if the receiver has already been started and
* still runs code (hasn't died yet). Returns <code>false</code> either if
* the receiver hasn't been started yet or if it has already started and run
* to completion and died.
*
* @return a <code>boolean</code> indicating the liveness of the Thread
* @see Thread#start
*/
public final boolean isAlive() {
return (vmThread != null);
} /**
* Returns a <code>boolean</code> indicating whether the receiver is a
* daemon Thread (<code>true</code>) or not (<code>false</code>) A
* daemon Thread only runs as long as there are non-daemon Threads running.
* When the last non-daemon Thread ends, the whole program ends no matter if
* it had daemon Threads still running or not.
*
* @return a <code>boolean</code> indicating whether the Thread is a daemon
* @see Thread#setDaemon
*/
public final boolean isDaemon() {
return daemon;
} /**
* Returns a <code>boolean</code> indicating whether the receiver has a
* pending interrupt request (<code>true</code>) or not (
* <code>false</code>)
*
* @return a <code>boolean</code> indicating the interrupt status
* @see Thread#interrupt
* @see Thread#interrupted
*/
public boolean isInterrupted() {
VMThread vmt = this.vmThread;
if (vmt != null) {
return vmt.isInterrupted();
} return false;
} /**
* Blocks the current Thread (<code>Thread.currentThread()</code>) until
* the receiver finishes its execution and dies.
*
* @throws InterruptedException if <code>interrupt()</code> was called for
* the receiver while it was in the <code>join()</code> call
* @see Object#notifyAll
* @see java.lang.ThreadDeath
*/
public final void join() throws InterruptedException {
VMThread t = vmThread;
if (t == null) {
return;
} synchronized (t) {
while (isAlive()) {
t.wait();
}
}
} /**
* Blocks the current Thread (<code>Thread.currentThread()</code>) until
* the receiver finishes its execution and dies or the specified timeout
* expires, whatever happens first.
*
* @param millis The maximum time to wait (in milliseconds).
* @throws InterruptedException if <code>interrupt()</code> was called for
* the receiver while it was in the <code>join()</code> call
* @see Object#notifyAll
* @see java.lang.ThreadDeath
*/
public final void join(long millis) throws InterruptedException {
join(millis, 0);
} /**
* Blocks the current Thread (<code>Thread.currentThread()</code>) until
* the receiver finishes its execution and dies or the specified timeout
* expires, whatever happens first.
*
* @param millis The maximum time to wait (in milliseconds).
* @param nanos Extra nanosecond precision
* @throws InterruptedException if <code>interrupt()</code> was called for
* the receiver while it was in the <code>join()</code> call
* @see Object#notifyAll
* @see java.lang.ThreadDeath
*/
public final void join(long millis, int nanos) throws InterruptedException {
if (millis < 0 || nanos < 0 || nanos >= NANOS_PER_MILLI) {
throw new IllegalArgumentException();
} // avoid overflow: if total > 292,277 years, just wait forever
boolean overflow = millis >= (Long.MAX_VALUE - nanos) / NANOS_PER_MILLI;
boolean forever = (millis | nanos) == 0;
if (forever | overflow) {
join();
return;
} VMThread t = vmThread;
if (t == null) {
return;
} synchronized (t) {
if (!isAlive()) {
return;
} // guaranteed not to overflow
long nanosToWait = millis * NANOS_PER_MILLI + nanos; // wait until this thread completes or the timeout has elapsed
long start = System.nanoTime();
while (true) {
t.wait(millis, nanos);
if (!isAlive()) {
break;
}
long nanosElapsed = System.nanoTime() - start;
long nanosRemaining = nanosToWait - nanosElapsed;
if (nanosRemaining <= 0) {
break;
}
millis = nanosRemaining / NANOS_PER_MILLI;
nanos = (int) (nanosRemaining - millis * NANOS_PER_MILLI);
}
}
} /**
* Throws {@code UnsupportedOperationException}.
*
* @see Thread#suspend()
* @deprecated Used with deprecated method {@link Thread#suspend}
*/
@Deprecated
public final void resume() {
throw new UnsupportedOperationException();
} /**
* Calls the <code>run()</code> method of the Runnable object the receiver
* holds. If no Runnable is set, does nothing.
*
* @see Thread#start
*/
public void run() {
if (target != null) {
target.run();
}
} /**
* Set the context ClassLoader for the receiver.
*
* @param cl The context ClassLoader
* @see #getContextClassLoader()
*/
public void setContextClassLoader(ClassLoader cl) {
contextClassLoader = cl;
} /**
* Set if the receiver is a daemon Thread or not. This can only be done
* before the Thread starts running.
*
* @param isDaemon
* indicates whether the Thread should be daemon or not
* @see Thread#isDaemon
*/
public final void setDaemon(boolean isDaemon) {
if (hasBeenStarted) {
throw new IllegalThreadStateException("Thread already started."); // TODO Externalize?
} if (vmThread == null) {
daemon = isDaemon;
}
} /**
* Sets the default uncaught exception handler. This handler is invoked in
* case any Thread dies due to an unhandled exception.
*
* @param handler
* The handler to set or null.
*/
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler) {
Thread.defaultUncaughtHandler = handler;
} /**
* Adds a runnable to be invoked upon interruption. If this thread has
* already been interrupted, the runnable will be invoked immediately. The
* action should be idempotent as it may be invoked multiple times for a
* single interruption.
*
* <p>Each call to this method must be matched with a corresponding call to
* {@link #popInterruptAction$}.
*
* @hide used by NIO
*/
public final void pushInterruptAction$(Runnable interruptAction) {
synchronized (interruptActions) {
interruptActions.add(interruptAction);
} if (interruptAction != null && isInterrupted()) {
interruptAction.run();
}
} /**
* Removes {@code interruptAction} so it is not invoked upon interruption.
*
* @param interruptAction the pushed action, used to check that the call
* stack is correctly nested.
*
* @hide used by NIO
*/
public final void popInterruptAction$(Runnable interruptAction) {
synchronized (interruptActions) {
Runnable removed = interruptActions.remove(interruptActions.size() - 1);
if (interruptAction != removed) {
throw new IllegalArgumentException(
"Expected " + interruptAction + " but was " + removed);
}
}
} /**
* Sets the name of the Thread.
*
* @param threadName the new name for the Thread
* @see Thread#getName
*/
public final void setName(String threadName) {
if (threadName == null) {
throw new NullPointerException();
} name = threadName;
VMThread vmt = this.vmThread;
if (vmt != null) {
/* notify the VM that the thread name has changed */
vmt.nameChanged(threadName);
}
} /**
* Sets the priority of the Thread. Note that the final priority set may not
* be the parameter that was passed - it will depend on the receiver's
* ThreadGroup. The priority cannot be set to be higher than the receiver's
* ThreadGroup's maxPriority().
*
* @param priority
* new priority for the Thread
* @throws IllegalArgumentException
* if the new priority is greater than Thread.MAX_PRIORITY or
* less than Thread.MIN_PRIORITY
* @see Thread#getPriority
*/
public final void setPriority(int priority) {
if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
throw new IllegalArgumentException("Priority out of range"); // TODO Externalize?
} if (priority > group.getMaxPriority()) {
priority = group.getMaxPriority();
} this.priority = priority; VMThread vmt = this.vmThread;
if (vmt != null) {
vmt.setPriority(priority);
}
} /**
* <p>
* Sets the uncaught exception handler. This handler is invoked in case this
* Thread dies due to an unhandled exception.
* </p>
*
* @param handler
* The handler to set or <code>null</code>.
*/
public void setUncaughtExceptionHandler(UncaughtExceptionHandler handler) {
uncaughtHandler = handler;
} /**
* Causes the thread which sent this message to sleep for the given interval
* of time (given in milliseconds). The precision is not guaranteed - the
* Thread may sleep more or less than requested.
*
* @param time
* The time to sleep in milliseconds.
* @throws InterruptedException
* if <code>interrupt()</code> was called for this Thread while
* it was sleeping
* @see Thread#interrupt()
*/
public static void sleep(long time) throws InterruptedException {
Thread.sleep(time, 0);
} /**
* Causes the thread which sent this message to sleep for the given interval
* of time (given in milliseconds and nanoseconds). The precision is not
* guaranteed - the Thread may sleep more or less than requested.
*
* @param millis
* The time to sleep in milliseconds.
* @param nanos
* Extra nanosecond precision
* @throws InterruptedException
* if <code>interrupt()</code> was called for this Thread while
* it was sleeping
* @see Thread#interrupt()
*/
public static void sleep(long millis, int nanos) throws InterruptedException {
VMThread.sleep(millis, nanos);
} /**
* Starts the new Thread of execution. The <code>run()</code> method of
* the receiver will be called by the receiver Thread itself (and not the
* Thread calling <code>start()</code>).
*
* @throws IllegalThreadStateException if the Thread has been started before
*
* @see Thread#run
*/
public synchronized void start() {
if (hasBeenStarted) {
throw new IllegalThreadStateException("Thread already started."); // TODO Externalize?
} hasBeenStarted = true; VMThread.create(this, stackSize);
} /**
* Requests the receiver Thread to stop and throw ThreadDeath. The Thread is
* resumed if it was suspended and awakened if it was sleeping, so that it
* can proceed to throw ThreadDeath.
*
* @deprecated because stopping a thread in this manner is unsafe and can
* leave your application and the VM in an unpredictable state.
*/
@Deprecated
public final void stop() {
stop(new ThreadDeath());
} /**
* Throws {@code UnsupportedOperationException}.
*
* @throws NullPointerException if <code>throwable()</code> is
* <code>null</code>
* @deprecated because stopping a thread in this manner is unsafe and can
* leave your application and the VM in an unpredictable state.
*/
@Deprecated
public final synchronized void stop(Throwable throwable) {
throw new UnsupportedOperationException();
} /**
* Throws {@code UnsupportedOperationException}.
*
* @see Thread#resume()
* @deprecated May cause deadlocks.
*/
@Deprecated
public final void suspend() {
throw new UnsupportedOperationException();
} /**
* Returns a string containing a concise, human-readable description of the
* Thread. It includes the Thread's name, priority, and group name.
*
* @return a printable representation for the receiver.
*/
@Override
public String toString() {
return "Thread[" + name + "," + priority + "," + group.getName() + "]";
} /**
* Causes the calling Thread to yield execution time to another Thread that
* is ready to run. The actual scheduling is implementation-dependent.
*/
public static void yield() {
VMThread.yield();
} /**
* Indicates whether the current Thread has a monitor lock on the specified
* object.
*
* @param object the object to test for the monitor lock
* @return true if the current thread has a monitor lock on the specified
* object; false otherwise
*/
public static boolean holdsLock(Object object) {
return currentThread().vmThread.holdsLock(object);
} /**
* Implemented by objects that want to handle cases where a thread is being
* terminated by an uncaught exception. Upon such termination, the handler
* is notified of the terminating thread and causal exception. If there is
* no explicit handler set then the thread's group is the default handler.
*/
public static interface UncaughtExceptionHandler {
/**
* The thread is being terminated by an uncaught exception. Further
* exceptions thrown in this method are prevent the remainder of the
* method from executing, but are otherwise ignored.
*
* @param thread the thread that has an uncaught exception
* @param ex the exception that was thrown
*/
void uncaughtException(Thread thread, Throwable ex);
} /**
* Unparks this thread. This unblocks the thread it if it was
* previously parked, or indicates that the thread is "preemptively
* unparked" if it wasn't already parked. The latter means that the
* next time the thread is told to park, it will merely clear its
* latent park bit and carry on without blocking.
*
* <p>See {@link java.util.concurrent.locks.LockSupport} for more
* in-depth information of the behavior of this method.</p>
*
* @hide for Unsafe
*/
public void unpark() {
VMThread vmt = vmThread; if (vmt == null) {
/*
* vmThread is null before the thread is start()ed. In
* this case, we just go ahead and set the state to
* PREEMPTIVELY_UNPARKED. Since this happens before the
* thread is started, we don't have to worry about
* synchronizing with it.
*/
parkState = ParkState.PREEMPTIVELY_UNPARKED;
return;
} synchronized (vmt) {
switch (parkState) {
case ParkState.PREEMPTIVELY_UNPARKED: {
/*
* Nothing to do in this case: By definition, a
* preemptively unparked thread is to remain in
* the preemptively unparked state if it is told
* to unpark.
*/
break;
}
case ParkState.UNPARKED: {
parkState = ParkState.PREEMPTIVELY_UNPARKED;
break;
}
default /*parked*/: {
parkState = ParkState.UNPARKED;
vmt.notifyAll();
break;
}
}
}
} /**
* Parks the current thread for a particular number of nanoseconds, or
* indefinitely. If not indefinitely, this method unparks the thread
* after the given number of nanoseconds if no other thread unparks it
* first. If the thread has been "preemptively unparked," this method
* cancels that unparking and returns immediately. This method may
* also return spuriously (that is, without the thread being told to
* unpark and without the indicated amount of time elapsing).
*
* <p>See {@link java.util.concurrent.locks.LockSupport} for more
* in-depth information of the behavior of this method.</p>
*
* <p>This method must only be called when <code>this</code> is the current
* thread.
*
* @param nanos number of nanoseconds to park for or <code>0</code>
* to park indefinitely
* @throws IllegalArgumentException thrown if <code>nanos &lt; 0</code>
*
* @hide for Unsafe
*/
public void parkFor(long nanos) {
VMThread vmt = vmThread; if (vmt == null) {
// Running threads should always have an associated vmThread.
throw new AssertionError();
} synchronized (vmt) {
switch (parkState) {
case ParkState.PREEMPTIVELY_UNPARKED: {
parkState = ParkState.UNPARKED;
break;
}
case ParkState.UNPARKED: {
long millis = nanos / NANOS_PER_MILLI;
nanos %= NANOS_PER_MILLI; parkState = ParkState.PARKED;
try {
vmt.wait(millis, (int) nanos);
} catch (InterruptedException ex) {
interrupt();
} finally {
/*
* Note: If parkState manages to become
* PREEMPTIVELY_UNPARKED before hitting this
* code, it should left in that state.
*/
if (parkState == ParkState.PARKED) {
parkState = ParkState.UNPARKED;
}
}
break;
}
default /*parked*/: {
throw new AssertionError(
"shouldn't happen: attempt to repark");
}
}
}
} /**
* Parks the current thread until the specified system time. This
* method attempts to unpark the current thread immediately after
* <code>System.currentTimeMillis()</code> reaches the specified
* value, if no other thread unparks it first. If the thread has
* been "preemptively unparked," this method cancels that
* unparking and returns immediately. This method may also return
* spuriously (that is, without the thread being told to unpark
* and without the indicated amount of time elapsing).
*
* <p>See {@link java.util.concurrent.locks.LockSupport} for more
* in-depth information of the behavior of this method.</p>
*
* <p>This method must only be called when <code>this</code> is the
* current thread.
*
* @param time the time after which the thread should be unparked,
* in absolute milliseconds-since-the-epoch
*
* @hide for Unsafe
*/
public void parkUntil(long time) {
VMThread vmt = vmThread; if (vmt == null) {
// Running threads should always have an associated vmThread.
throw new AssertionError();
} synchronized (vmt) {
/*
* Note: This conflates the two time bases of "wall clock"
* time and "monotonic uptime" time. However, given that
* the underlying system can only wait on monotonic time,
* it is unclear if there is any way to avoid the
* conflation. The downside here is that if, having
* calculated the delay, the wall clock gets moved ahead,
* this method may not return until well after the wall
* clock has reached the originally designated time. The
* reverse problem (the wall clock being turned back)
* isn't a big deal, since this method is allowed to
* spuriously return for any reason, and this situation
* can safely be construed as just such a spurious return.
*/
long delayMillis = time - System.currentTimeMillis(); if (delayMillis <= 0) {
parkState = ParkState.UNPARKED;
} else {
parkFor(delayMillis * NANOS_PER_MILLI);
}
}
}
}

Thread Local

 /*
* Copyright (C) 2008 The Android Open Source Project
*
* 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 java.lang; import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.concurrent.atomic.AtomicInteger; /**
* Implements a thread-local storage, that is, a variable for which each thread
* has its own value. All threads share the same {@code ThreadLocal} object,
* but each sees a different value when accessing it, and changes made by one
* thread do not affect the other threads. The implementation supports
* {@code null} values.
*
* @see java.lang.Thread
* @author Bob Lee
*/
public class ThreadLocal<T> { /* Thanks to Josh Bloch and Doug Lea for code reviews and impl advice. */ /**
* Creates a new thread-local variable.
*/
public ThreadLocal() {} /**
* Returns the value of this variable for the current thread. If an entry
* doesn't yet exist for this variable on this thread, this method will
* create an entry, populating the value with the result of
* {@link #initialValue()}.
*
* @return the current value of the variable for the calling thread.
*/
@SuppressWarnings("unchecked")
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
} return (T) values.getAfterMiss(this);
} /**
* Provides the initial value of this variable for the current thread.
* The default implementation returns {@code null}.
*
* @return the initial value of the variable.
*/
protected T initialValue() {
return null;
} /**
* Sets the value of this variable for the current thread. If set to
* {@code null}, the value will be set to null and the underlying entry will
* still be present.
*
* @param value the new value of the variable for the caller thread.
*/
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
} /**
* Removes the entry for this variable in the current thread. If this call
* is followed by a {@link #get()} before a {@link #set},
* {@code #get()} will call {@link #initialValue()} and create a new
* entry with the resulting value.
*
* @since 1.5
*/
public void remove() {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
values.remove(this);
}
} /**
* Creates Values instance for this thread and variable type.
*/
Values initializeValues(Thread current) {
return current.localValues = new Values();
} /**
* Gets Values instance for this thread and variable type.
*/
Values values(Thread current) {
return current.localValues;
} /** Weak reference to this thread local instance. */
private final Reference<ThreadLocal<T>> reference
= new WeakReference<ThreadLocal<T>>(this); /** Hash counter. */
private static AtomicInteger hashCounter = new AtomicInteger(0); /**
* Internal hash. We deliberately don't bother with #hashCode().
* Hashes must be even. This ensures that the result of
* (hash & (table.length - 1)) points to a key and not a value.
*
* We increment by Doug Lea's Magic Number(TM) (*2 since keys are in
* every other bucket) to help prevent clustering.
*/
private final int hash = hashCounter.getAndAdd(0x61c88647 * 2); /**
* Per-thread map of ThreadLocal instances to values.
*/
static class Values { /**
* Size must always be a power of 2.
*/
private static final int INITIAL_SIZE = 16; /**
* Placeholder for deleted entries.
*/
private static final Object TOMBSTONE = new Object(); /**
* Map entries. Contains alternating keys (ThreadLocal) and values.
* The length is always a power of 2.
*/
private Object[] table; /** Used to turn hashes into indices. */
private int mask; /** Number of live entries. */
private int size; /** Number of tombstones. */
private int tombstones; /** Maximum number of live entries and tombstones. */
private int maximumLoad; /** Points to the next cell to clean up. */
private int clean; /**
* Constructs a new, empty instance.
*/
Values() {
initializeTable(INITIAL_SIZE);
this.size = 0;
this.tombstones = 0;
} /**
* Used for InheritableThreadLocals.
*/
Values(Values fromParent) {
this.table = fromParent.table.clone();
this.mask = fromParent.mask;
this.size = fromParent.size;
this.tombstones = fromParent.tombstones;
this.maximumLoad = fromParent.maximumLoad;
this.clean = fromParent.clean;
inheritValues(fromParent);
} /**
* Inherits values from a parent thread.
*/
@SuppressWarnings({"unchecked"})
private void inheritValues(Values fromParent) {
// Transfer values from parent to child thread.
Object[] table = this.table;
for (int i = table.length - 2; i >= 0; i -= 2) {
Object k = table[i]; if (k == null || k == TOMBSTONE) {
// Skip this entry.
continue;
} // The table can only contain null, tombstones and references.
Reference<InheritableThreadLocal<?>> reference
= (Reference<InheritableThreadLocal<?>>) k;
// Raw type enables us to pass in an Object below.
InheritableThreadLocal key = reference.get();
if (key != null) {
// Replace value with filtered value.
// We should just let exceptions bubble out and tank
// the thread creation
table[i + 1] = key.childValue(fromParent.table[i + 1]);
} else {
// The key was reclaimed.
table[i] = TOMBSTONE;
table[i + 1] = null;
fromParent.table[i] = TOMBSTONE;
fromParent.table[i + 1] = null; tombstones++;
fromParent.tombstones++; size--;
fromParent.size--;
}
}
} /**
* Creates a new, empty table with the given capacity.
*/
private void initializeTable(int capacity) {
this.table = new Object[capacity * 2];
this.mask = table.length - 1;
this.clean = 0;
this.maximumLoad = capacity * 2 / 3; // 2/3
} /**
* Cleans up after garbage-collected thread locals.
*/
private void cleanUp() {
if (rehash()) {
// If we rehashed, we needn't clean up (clean up happens as
// a side effect).
return;
} if (size == 0) {
// No live entries == nothing to clean.
return;
} // Clean log(table.length) entries picking up where we left off
// last time.
int index = clean;
Object[] table = this.table;
for (int counter = table.length; counter > 0; counter >>= 1,
index = next(index)) {
Object k = table[index]; if (k == TOMBSTONE || k == null) {
continue; // on to next entry
} // The table can only contain null, tombstones and references.
@SuppressWarnings("unchecked")
Reference<ThreadLocal<?>> reference
= (Reference<ThreadLocal<?>>) k;
if (reference.get() == null) {
// This thread local was reclaimed by the garbage collector.
table[index] = TOMBSTONE;
table[index + 1] = null;
tombstones++;
size--;
}
} // Point cursor to next index.
clean = index;
} /**
* Rehashes the table, expanding or contracting it as necessary.
* Gets rid of tombstones. Returns true if a rehash occurred.
* We must rehash every time we fill a null slot; we depend on the
* presence of null slots to end searches (otherwise, we'll infinitely
* loop).
*/
private boolean rehash() {
if (tombstones + size < maximumLoad) {
return false;
} int capacity = table.length >> 1; // Default to the same capacity. This will create a table of the
// same size and move over the live entries, analogous to a
// garbage collection. This should only happen if you churn a
// bunch of thread local garbage (removing and reinserting
// the same thread locals over and over will overwrite tombstones
// and not fill up the table).
int newCapacity = capacity; if (size > (capacity >> 1)) {
// More than 1/2 filled w/ live entries.
// Double size.
newCapacity = capacity * 2;
} Object[] oldTable = this.table; // Allocate new table.
initializeTable(newCapacity); // We won't have any tombstones after this.
this.tombstones = 0; // If we have no live entries, we can quit here.
if (size == 0) {
return true;
} // Move over entries.
for (int i = oldTable.length - 2; i >= 0; i -= 2) {
Object k = oldTable[i];
if (k == null || k == TOMBSTONE) {
// Skip this entry.
continue;
} // The table can only contain null, tombstones and references.
@SuppressWarnings("unchecked")
Reference<ThreadLocal<?>> reference
= (Reference<ThreadLocal<?>>) k;
ThreadLocal<?> key = reference.get();
if (key != null) {
// Entry is still live. Move it over.
add(key, oldTable[i + 1]);
} else {
// The key was reclaimed.
size--;
}
} return true;
} /**
* Adds an entry during rehashing. Compared to put(), this method
* doesn't have to clean up, check for existing entries, account for
* tombstones, etc.
*/
void add(ThreadLocal<?> key, Object value) {
for (int index = key.hash & mask;; index = next(index)) {
Object k = table[index];
if (k == null) {
table[index] = key.reference;
table[index + 1] = value;
return;
}
}
} /**
* Sets entry for given ThreadLocal to given value, creating an
* entry if necessary.
*/
void put(ThreadLocal<?> key, Object value) {
cleanUp(); // Keep track of first tombstone. That's where we want to go back
// and add an entry if necessary.
int firstTombstone = -1; for (int index = key.hash & mask;; index = next(index)) {
Object k = table[index]; if (k == key.reference) {
// Replace existing entry.
table[index + 1] = value;
return;
} if (k == null) {
if (firstTombstone == -1) {
// Fill in null slot.
table[index] = key.reference;
table[index + 1] = value;
size++;
return;
} // Go back and replace first tombstone.
table[firstTombstone] = key.reference;
table[firstTombstone + 1] = value;
tombstones--;
size++;
return;
} // Remember first tombstone.
if (firstTombstone == -1 && k == TOMBSTONE) {
firstTombstone = index;
}
}
} /**
* Gets value for given ThreadLocal after not finding it in the first
* slot.
*/
Object getAfterMiss(ThreadLocal<?> key) {
Object[] table = this.table;
int index = key.hash & mask; // If the first slot is empty, the search is over.
if (table[index] == null) {
Object value = key.initialValue(); // If the table is still the same and the slot is still empty...
if (this.table == table && table[index] == null) {
table[index] = key.reference;
table[index + 1] = value;
size++; cleanUp();
return value;
} // The table changed during initialValue().
put(key, value);
return value;
} // Keep track of first tombstone. That's where we want to go back
// and add an entry if necessary.
int firstTombstone = -1; // Continue search.
for (index = next(index);; index = next(index)) {
Object reference = table[index];
if (reference == key.reference) {
return table[index + 1];
} // If no entry was found...
if (reference == null) {
Object value = key.initialValue(); // If the table is still the same...
if (this.table == table) {
// If we passed a tombstone and that slot still
// contains a tombstone...
if (firstTombstone > -1
&& table[firstTombstone] == TOMBSTONE) {
table[firstTombstone] = key.reference;
table[firstTombstone + 1] = value;
tombstones--;
size++; // No need to clean up here. We aren't filling
// in a null slot.
return value;
} // If this slot is still empty...
if (table[index] == null) {
table[index] = key.reference;
table[index + 1] = value;
size++; cleanUp();
return value;
}
} // The table changed during initialValue().
put(key, value);
return value;
} if (firstTombstone == -1 && reference == TOMBSTONE) {
// Keep track of this tombstone so we can overwrite it.
firstTombstone = index;
}
}
} /**
* Removes entry for the given ThreadLocal.
*/
void remove(ThreadLocal<?> key) {
cleanUp(); for (int index = key.hash & mask;; index = next(index)) {
Object reference = table[index]; if (reference == key.reference) {
// Success!
table[index] = TOMBSTONE;
table[index + 1] = null;
tombstones++;
size--;
return;
} if (reference == null) {
// No entry found.
return;
}
}
} /**
* Gets the next index. If we're at the end of the table, we wrap back
* around to 0.
*/
private int next(int index) {
return (index + 2) & mask;
}
}
}

Thead Group

 /*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 java.lang; import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import libcore.util.CollectionUtils; /**
* {@code ThreadGroup} is a means of organizing threads into a hierarchical structure.
* This class is obsolete. See <i>Effective Java</i> Item 73, "Avoid thread groups" for details.
* @see Thread
*/
public class ThreadGroup implements Thread.UncaughtExceptionHandler { // Name of this ThreadGroup
// VM needs this field name for debugging.
private String name; // Maximum priority for Threads inside this ThreadGroup
private int maxPriority = Thread.MAX_PRIORITY; // The ThreadGroup to which this ThreadGroup belongs
// VM needs this field name for debugging.
final ThreadGroup parent; /**
* Weak references to the threads in this group.
* Access is guarded by synchronizing on this field.
*/
private final List<WeakReference<Thread>> threadRefs = new ArrayList<WeakReference<Thread>>(5); /**
* View of the threads.
* Access is guarded by synchronizing on threadRefs.
*/
private final Iterable<Thread> threads = CollectionUtils.dereferenceIterable(threadRefs, true); /**
* Thread groups. Access is guarded by synchronizing on this field.
*/
private final List<ThreadGroup> groups = new ArrayList<ThreadGroup>(3); // Whether this ThreadGroup is a daemon ThreadGroup or not
private boolean isDaemon; // Whether this ThreadGroup has already been destroyed or not
private boolean isDestroyed; /* the VM uses these directly; do not rename */
static final ThreadGroup mSystem = new ThreadGroup();
static final ThreadGroup mMain = new ThreadGroup(mSystem, "main"); /**
* Constructs a new {@code ThreadGroup} with the given name. The new {@code ThreadGroup}
* will be child of the {@code ThreadGroup} to which the calling thread belongs.
*
* @param name the name
* @see Thread#currentThread
*/
public ThreadGroup(String name) {
this(Thread.currentThread().getThreadGroup(), name);
} /**
* Constructs a new {@code ThreadGroup} with the given name, as a child of the
* given {@code ThreadGroup}.
*
* @param parent the parent
* @param name the name
* @throws NullPointerException if {@code parent == null}
* @throws IllegalThreadStateException if {@code parent} has been
* destroyed already
*/
public ThreadGroup(ThreadGroup parent, String name) {
if (parent == null) {
throw new NullPointerException("parent == null");
}
this.name = name;
this.parent = parent;
if (parent != null) {
parent.add(this);
this.setMaxPriority(parent.getMaxPriority());
if (parent.isDaemon()) {
this.setDaemon(true);
}
}
} /**
* Initialize the special "system" ThreadGroup. Was "main" in Harmony,
* but we have an additional group above that in Android.
*/
private ThreadGroup() {
this.name = "system";
this.parent = null;
} /**
* Returns the number of running {@code Thread}s which are children of this thread group,
* directly or indirectly.
*
* @return the number of children
*/
public int activeCount() {
int count = 0;
synchronized (threadRefs) {
for (Thread thread : threads) {
if (thread.isAlive()) {
count++;
}
}
}
synchronized (groups) {
for (ThreadGroup group : groups) {
count += group.activeCount();
}
}
return count;
} /**
* Returns the number of {@code ThreadGroup}s which are children of this group,
* directly or indirectly.
*
* @return the number of children
*/
public int activeGroupCount() {
int count = 0;
synchronized (groups) {
for (ThreadGroup group : groups) {
// One for this group & the subgroups
count += 1 + group.activeGroupCount();
}
}
return count;
} /**
* Adds a {@code ThreadGroup} to this thread group.
*
* @param g ThreadGroup to add
* @throws IllegalThreadStateException if this group has been destroyed already
*/
private void add(ThreadGroup g) throws IllegalThreadStateException {
synchronized (groups) {
if (isDestroyed) {
throw new IllegalThreadStateException();
}
groups.add(g);
}
} /**
* Does nothing. The definition of this method depends on the deprecated
* method {@link #suspend()}. The exact behavior of this call was never
* specified.
*
* @param b Used to control low memory implicit suspension
* @return {@code true} (always)
*
* @deprecated Required deprecated method suspend().
*/
@Deprecated
public boolean allowThreadSuspension(boolean b) {
// Does not apply to this VM, no-op
return true;
} /**
* Does nothing.
*/
public final void checkAccess() {
} /**
* Destroys this thread group and recursively all its subgroups. It is only legal
* to destroy a {@code ThreadGroup} that has no threads in it. Any daemon
* {@code ThreadGroup} is destroyed automatically when it becomes empty (no threads
* or thread groups in it).
*
* @throws IllegalThreadStateException if this thread group or any of its
* subgroups has been destroyed already or if it still contains
* threads.
*/
public final void destroy() {
synchronized (threadRefs) {
synchronized (groups) {
if (isDestroyed) {
throw new IllegalThreadStateException(
"Thread group was already destroyed: "
+ (this.name != null ? this.name : "n/a"));
}
if (threads.iterator().hasNext()) {
throw new IllegalThreadStateException(
"Thread group still contains threads: "
+ (this.name != null ? this.name : "n/a"));
}
// Call recursively for subgroups
while (!groups.isEmpty()) {
// We always get the first element - remember, when the
// child dies it removes itself from our collection. See
// below.
groups.get(0).destroy();
} if (parent != null) {
parent.remove(this);
} // Now that the ThreadGroup is really destroyed it can be tagged as so
this.isDestroyed = true;
}
}
} /*
* Auxiliary method that destroys this thread group and recursively all its
* subgroups if this is a daemon ThreadGroup.
*
* @see #destroy
* @see #setDaemon
* @see #isDaemon
*/
private void destroyIfEmptyDaemon() {
// Has to be non-destroyed daemon to make sense
synchronized (threadRefs) {
if (isDaemon && !isDestroyed && !threads.iterator().hasNext()) {
synchronized (groups) {
if (groups.isEmpty()) {
destroy();
}
}
}
}
} /**
* Iterates over all active threads in this group (and its sub-groups) and
* stores the threads in the given array. Returns when the array is full or
* no more threads remain, whichever happens first.
*
* <p>Note that this method will silently ignore any threads that don't fit in the
* supplied array.
*
* @param threads the array into which the {@code Thread}s will be copied
* @return the number of {@code Thread}s that were copied
*/
public int enumerate(Thread[] threads) {
return enumerate(threads, true);
} /**
* Iterates over all active threads in this group (and, optionally, its
* sub-groups) and stores the threads in the given array. Returns when the
* array is full or no more threads remain, whichever happens first.
*
* <p>Note that this method will silently ignore any threads that don't fit in the
* supplied array.
*
* @param threads the array into which the {@code Thread}s will be copied
* @param recurse indicates whether {@code Thread}s in subgroups should be
* recursively copied as well
* @return the number of {@code Thread}s that were copied
*/
public int enumerate(Thread[] threads, boolean recurse) {
return enumerateGeneric(threads, recurse, 0, true);
} /**
* Iterates over all thread groups in this group (and its sub-groups) and
* and stores the groups in the given array. Returns when the array is full
* or no more groups remain, whichever happens first.
*
* <p>Note that this method will silently ignore any thread groups that don't fit in the
* supplied array.
*
* @param groups the array into which the {@code ThreadGroup}s will be copied
* @return the number of {@code ThreadGroup}s that were copied
*/
public int enumerate(ThreadGroup[] groups) {
return enumerate(groups, true);
} /**
* Iterates over all thread groups in this group (and, optionally, its
* sub-groups) and stores the groups in the given array. Returns when
* the array is full or no more groups remain, whichever happens first.
*
* <p>Note that this method will silently ignore any thread groups that don't fit in the
* supplied array.
*
* @param groups the array into which the {@code ThreadGroup}s will be copied
* @param recurse indicates whether {@code ThreadGroup}s in subgroups should be
* recursively copied as well or not
* @return the number of {@code ThreadGroup}s that were copied
*/
public int enumerate(ThreadGroup[] groups, boolean recurse) {
return enumerateGeneric(groups, recurse, 0, false);
} /**
* Copies into <param>enumeration</param> starting at
* <param>enumerationIndex</param> all Threads or ThreadGroups in the
* receiver. If <param>recurse</param> is true, recursively enumerate the
* elements in subgroups.
*
* If the array passed as parameter is too small no exception is thrown -
* the extra elements are simply not copied.
*
* @param enumeration array into which the elements will be copied
* @param recurse Indicates whether subgroups should be enumerated or not
* @param enumerationIndex Indicates in which position of the enumeration
* array we are
* @param enumeratingThreads Indicates whether we are enumerating Threads or
* ThreadGroups
* @return How many elements were enumerated/copied over
*/
private int enumerateGeneric(Object[] enumeration, boolean recurse, int enumerationIndex,
boolean enumeratingThreads) {
if (enumeratingThreads) {
synchronized (threadRefs) {
// walk the references directly so we can iterate in reverse order
for (int i = threadRefs.size() - 1; i >= 0; --i) {
Thread thread = threadRefs.get(i).get();
if (thread != null && thread.isAlive()) {
if (enumerationIndex >= enumeration.length) {
return enumerationIndex;
}
enumeration[enumerationIndex++] = thread;
}
}
}
} else {
synchronized (groups) {
for (int i = groups.size() - 1; i >= 0; --i) {
if (enumerationIndex >= enumeration.length) {
return enumerationIndex;
}
enumeration[enumerationIndex++] = groups.get(i);
}
}
} if (recurse) {
synchronized (groups) {
for (ThreadGroup group : groups) {
if (enumerationIndex >= enumeration.length) {
return enumerationIndex;
}
enumerationIndex = group.enumerateGeneric(enumeration, recurse,
enumerationIndex, enumeratingThreads);
}
}
}
return enumerationIndex;
} /**
* Returns the maximum allowed priority for a {@code Thread} in this thread group.
*
* @return the maximum priority
*
* @see #setMaxPriority
*/
public final int getMaxPriority() {
return maxPriority;
} /**
* Returns the name of this thread group.
*
* @return the group's name
*/
public final String getName() {
return name;
} /**
* Returns this thread group's parent {@code ThreadGroup}. It can be null if this
* is the the root ThreadGroup.
*
* @return the parent
*/
public final ThreadGroup getParent() {
return parent;
} /**
* Interrupts every {@code Thread} in this group and recursively in all its
* subgroups.
*
* @see Thread#interrupt
*/
public final void interrupt() {
synchronized (threadRefs) {
for (Thread thread : threads) {
thread.interrupt();
}
}
synchronized (groups) {
for (ThreadGroup group : groups) {
group.interrupt();
}
}
} /**
* Checks whether this thread group is a daemon {@code ThreadGroup}.
*
* @return true if this thread group is a daemon {@code ThreadGroup}
*
* @see #setDaemon
* @see #destroy
*/
public final boolean isDaemon() {
return isDaemon;
} /**
* Checks whether this thread group has already been destroyed.
*
* @return true if this thread group has already been destroyed
* @see #destroy
*/
public synchronized boolean isDestroyed() {
return isDestroyed;
} /**
* Outputs to {@code System.out} a text representation of the
* hierarchy of {@code Thread}s and {@code ThreadGroup}s in this thread group (and recursively).
* Proper indentation is used to show the nesting of groups inside groups
* and threads inside groups.
*/
public void list() {
// We start in a fresh line
System.out.println();
list(0);
} /*
* Outputs to {@code System.out}a text representation of the
* hierarchy of Threads and ThreadGroups in this thread group (and recursively).
* The indentation will be four spaces per level of nesting.
*
* @param levels How many levels of nesting, so that proper indentation can
* be output.
*/
private void list(int levels) {
indent(levels);
System.out.println(this.toString()); ++levels;
synchronized (threadRefs) {
for (Thread thread : threads) {
indent(levels);
System.out.println(thread);
}
}
synchronized (groups) {
for (ThreadGroup group : groups) {
group.list(levels);
}
}
} private void indent(int levels) {
for (int i = 0; i < levels; i++) {
System.out.print(" "); // 4 spaces for each level
}
} /**
* Checks whether this thread group is a direct or indirect parent group of a
* given {@code ThreadGroup}.
*
* @param g the potential child {@code ThreadGroup}
* @return true if this thread group is parent of {@code g}
*/
public final boolean parentOf(ThreadGroup g) {
while (g != null) {
if (this == g) {
return true;
}
g = g.parent;
}
return false;
} /**
* Removes an immediate subgroup.
*
* @param g ThreadGroup to remove
*
* @see #add(Thread)
* @see #add(ThreadGroup)
*/
private void remove(ThreadGroup g) {
synchronized (groups) {
for (Iterator<ThreadGroup> i = groups.iterator(); i.hasNext(); ) {
ThreadGroup threadGroup = i.next();
if (threadGroup.equals(g)) {
i.remove();
break;
}
}
}
destroyIfEmptyDaemon();
} /**
* Resumes every thread in this group and recursively in all its
* subgroups.
*
* @see Thread#resume
* @see #suspend
*
* @deprecated Requires deprecated method Thread.resume().
*/
@SuppressWarnings("deprecation")
@Deprecated
public final void resume() {
synchronized (threadRefs) {
for (Thread thread : threads) {
thread.resume();
}
}
synchronized (groups) {
for (ThreadGroup group : groups) {
group.resume();
}
}
} /**
* Sets whether this is a daemon {@code ThreadGroup} or not. Daemon
* thread groups are automatically destroyed when they become empty.
*
* @param isDaemon the new value
* @see #isDaemon
* @see #destroy
*/
public final void setDaemon(boolean isDaemon) {
this.isDaemon = isDaemon;
} /**
* Configures the maximum allowed priority for a {@code Thread} in this group and
* recursively in all its subgroups.
*
* <p>A caller can never increase the maximum priority of a thread group.
* Such an attempt will not result in an exception, it will
* simply leave the thread group with its current maximum priority.
*
* @param newMax the new maximum priority to be set
*
* @throws IllegalArgumentException if the new priority is greater than
* Thread.MAX_PRIORITY or less than Thread.MIN_PRIORITY
*
* @see #getMaxPriority
*/
public final void setMaxPriority(int newMax) {
if (newMax <= this.maxPriority) {
if (newMax < Thread.MIN_PRIORITY) {
newMax = Thread.MIN_PRIORITY;
} int parentPriority = parent == null ? newMax : parent.getMaxPriority();
this.maxPriority = parentPriority <= newMax ? parentPriority : newMax;
synchronized (groups) {
for (ThreadGroup group : groups) {
group.setMaxPriority(newMax);
}
}
}
} /**
* Stops every thread in this group and recursively in all its subgroups.
*
* @see Thread#stop()
* @see Thread#stop(Throwable)
* @see ThreadDeath
*
* @deprecated Requires deprecated method Thread.stop().
*/
@SuppressWarnings("deprecation")
@Deprecated
public final void stop() {
if (stopHelper()) {
Thread.currentThread().stop();
}
} @SuppressWarnings("deprecation")
private boolean stopHelper() {
boolean stopCurrent = false;
synchronized (threadRefs) {
Thread current = Thread.currentThread();
for (Thread thread : threads) {
if (thread == current) {
stopCurrent = true;
} else {
thread.stop();
}
}
}
synchronized (groups) {
for (ThreadGroup group : groups) {
stopCurrent |= group.stopHelper();
}
}
return stopCurrent;
} /**
* Suspends every thread in this group and recursively in all its
* subgroups.
*
* @see Thread#suspend
* @see #resume
*
* @deprecated Requires deprecated method Thread.suspend().
*/
@SuppressWarnings("deprecation")
@Deprecated
public final void suspend() {
if (suspendHelper()) {
Thread.currentThread().suspend();
}
} @SuppressWarnings("deprecation")
private boolean suspendHelper() {
boolean suspendCurrent = false;
synchronized (threadRefs) {
Thread current = Thread.currentThread();
for (Thread thread : threads) {
if (thread == current) {
suspendCurrent = true;
} else {
thread.suspend();
}
}
}
synchronized (groups) {
for (ThreadGroup group : groups) {
suspendCurrent |= group.suspendHelper();
}
}
return suspendCurrent;
} @Override
public String toString() {
return getClass().getName() + "[name=" + getName()
+ ",maxPriority=" + getMaxPriority() + "]";
} /**
* Handles uncaught exceptions. Any uncaught exception in any {@code Thread}
* is forwarded to the thread's {@code ThreadGroup} by invoking this
* method.
*
* <p>New code should use {@link Thread#setUncaughtExceptionHandler} instead of thread groups.
*
* @param t the Thread that terminated with an uncaught exception
* @param e the uncaught exception itself
*/
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else if (Thread.getDefaultUncaughtExceptionHandler() != null) {
// TODO The spec is unclear regarding this. What do we do?
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
// No parent group, has to be 'system' Thread Group
e.printStackTrace(System.err);
}
} /**
* Called by the Thread constructor.
*/
final void addThread(Thread thread) throws IllegalThreadStateException {
synchronized (threadRefs) {
if (isDestroyed) {
throw new IllegalThreadStateException();
}
threadRefs.add(new WeakReference<Thread>(thread));
}
} /**
* Called by the VM when a Thread dies.
*/
final void removeThread(Thread thread) throws IllegalThreadStateException {
synchronized (threadRefs) {
for (Iterator<Thread> i = threads.iterator(); i.hasNext(); ) {
if (i.next().equals(thread)) {
i.remove();
break;
}
}
}
destroyIfEmptyDaemon();
}
}

 VMThread

 /* VMThread -- VM interface for Thread of executable code
Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation This file is part of GNU Classpath. GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version. GNU Classpath 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
General Public License for more details. You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA. Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination. As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */ package java.lang; /**
* VM interface for Thread of executable code. Holds VM dependent state.
* It is deliberately package local and final and should only be accessed
* by the Thread class.
* <p>
* This is the GNU Classpath reference implementation, it should be adapted
* for a specific VM.
* <p>
* The following methods must be implemented:
* <ul>
* <li>native void start(long stacksize);
* <li>native void interrupt();
* <li>native boolean isInterrupted();
* <li>native void suspend();
* <li>native void resume();
* <li>native void nativeSetPriority(int priority);
* <li>native void nativeStop(Throwable t);
* <li>native static Thread currentThread();
* <li>static native void yield();
* <li>static native boolean interrupted();
* </ul>
* All other methods may be implemented to make Thread handling more efficient
* or to implement some optional (and sometimes deprecated) behaviour. Default
* implementations are provided but it is highly recommended to optimize them
* for a specific VM.
*
* @author Jeroen Frijters (jeroen@frijters.net)
* @author Dalibor Topic (robilad@kaffe.org)
*/
final class VMThread
{
/**
* The Thread object that this VM state belongs to.
* Used in currentThread() and start().
* Note: when this thread dies, this reference is *not* cleared
*/
volatile Thread thread; /**
* Flag that is set when the thread runs, used by stop() to protect against
* stop's getting lost.
*/
private volatile boolean running; /**
* VM private data.
*/
private transient Object vmdata; /**
* Private constructor, create VMThreads with the static create method.
*
* @param thread The Thread object that was just created.
*/
private VMThread(Thread thread)
{
this.thread = thread;
} /**
* This method is the initial Java code that gets executed when a native
* thread starts. It's job is to coordinate with the rest of the VMThread
* logic and to start executing user code and afterwards handle clean up.
*/
private void run()
{
try
{
try
{
running = true;
synchronized(thread)
{
Throwable t = thread.stillborn;
if(t != null)
{
thread.stillborn = null;
throw t;
}
}
thread.run();
}
catch(Throwable t)
{
try
{
Thread.UncaughtExceptionHandler handler;
handler = thread.getUncaughtExceptionHandler();
handler.uncaughtException(thread, t);
}
catch(Throwable ignore)
{
}
}
}
finally
{
// Setting runnable to false is partial protection against stop
// being called while we're cleaning up. To be safe all code in
// VMThread be unstoppable.
running = false;
thread.die();
synchronized(this)
{
// release the threads waiting to join us
notifyAll();
}
}
} /**
* Creates a native Thread. This is called from the start method of Thread.
* The Thread is started.
*
* @param thread The newly created Thread object
* @param stacksize Indicates the requested stacksize. Normally zero,
* non-zero values indicate requested stack size in bytes but it is up
* to the specific VM implementation to interpret them and may be ignored.
*/
static void create(Thread thread, long stacksize)
{
VMThread vmThread = new VMThread(thread);
vmThread.start(stacksize);
thread.vmThread = vmThread;
} /**
* Gets the name of the thread. Usually this is the name field of the
* associated Thread object, but some implementation might choose to
* return the name of the underlying platform thread.
*/
String getName()
{
return thread.name;
} /**
* Set the name of the thread. Usually this sets the name field of the
* associated Thread object, but some implementations might choose to
* set the name of the underlying platform thread.
* @param name The new name
*/
void setName(String name)
{
thread.name = name;
} /**
* Set the thread priority field in the associated Thread object and
* calls the native method to set the priority of the underlying
* platform thread.
* @param priority The new priority
*/
void setPriority(int priority)
{
thread.priority = priority;
nativeSetPriority(priority);
} /**
* Returns the priority. Usually this is the priority field from the
* associated Thread object, but some implementation might choose to
* return the priority of the underlying platform thread.
* @return this Thread's priority
*/
int getPriority()
{
return thread.priority;
} /**
* Returns true if the thread is a daemon thread. Usually this is the
* daemon field from the associated Thread object, but some
* implementation might choose to return the daemon state of the underlying
* platform thread.
* @return whether this is a daemon Thread or not
*/
boolean isDaemon()
{
return thread.daemon;
} /**
* Returns the number of stack frames in this Thread.
* Will only be called when when a previous call to suspend() returned true.
*
* @deprecated unsafe operation
*/
native int countStackFrames(); /**
* Wait the specified amount of time for the Thread in question to die.
*
* <p>Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do
* not offer that fine a grain of timing resolution. Besides, there is
* no guarantee that this thread can start up immediately when time expires,
* because some other thread may be active. So don't expect real-time
* performance.
*
* @param ms the number of milliseconds to wait, or 0 for forever
* @param ns the number of extra nanoseconds to sleep (0-999999)
* @throws InterruptedException if the Thread is interrupted; it's
* <i>interrupted status</i> will be cleared
*/
synchronized void join(long ms, int ns) throws InterruptedException
{
// Round up
ms += (ns != 0) ? 1 : 0; // Compute end time, but don't overflow
long now = System.currentTimeMillis();
long end = now + ms;
if (end < now)
end = Long.MAX_VALUE; // A VM is allowed to return from wait() without notify() having been
// called, so we loop to handle possible spurious wakeups.
while(thread.vmThread != null)
{
// We use the VMThread object to wait on, because this is a private
// object, so client code cannot call notify on us.
wait(ms);
if(ms != 0)
{
now = System.currentTimeMillis();
ms = end - now;
if(ms <= 0)
{
break;
}
}
}
} /**
* Cause this Thread to stop abnormally and throw the specified exception.
* If you stop a Thread that has not yet started, the stop is ignored
* (contrary to what the JDK documentation says).
* <b>WARNING</b>This bypasses Java security, and can throw a checked
* exception which the call stack is unprepared to handle. Do not abuse
* this power.
*
* <p>This is inherently unsafe, as it can interrupt synchronized blocks and
* leave data in bad states.
*
* <p><b>NOTE</b> stop() should take care not to stop a thread if it is
* executing code in this class.
*
* @param t the Throwable to throw when the Thread dies
* @deprecated unsafe operation, try not to use
*/
void stop(Throwable t)
{
// Note: we assume that we own the lock on thread
// (i.e. that Thread.stop() is synchronized)
if(running)
nativeStop(t);
else
thread.stillborn = t;
} /**
* Create a native thread on the underlying platform and start it executing
* on the run method of this object.
* @param stacksize the requested size of the native thread stack
*/
native void start(long stacksize); /**
* Interrupt this thread.
*/
native void interrupt(); /**
* Determine whether this Thread has been interrupted, but leave
* the <i>interrupted status</i> alone in the process.
*
* @return whether the Thread has been interrupted
*/
native boolean isInterrupted(); /**
* Suspend this Thread. It will not come back, ever, unless it is resumed.
*/
native void suspend(); /**
* Resume this Thread. If the thread is not suspended, this method does
* nothing.
*/
native void resume(); /**
* Set the priority of the underlying platform thread.
*
* @param priority the new priority
*/
native void nativeSetPriority(int priority); /**
* Asynchronously throw the specified throwable in this Thread.
*
* @param t the exception to throw
*/
native void nativeStop(Throwable t); /**
* Return the Thread object associated with the currently executing
* thread.
*
* @return the currently executing Thread
*/
static native Thread currentThread(); /**
* Yield to another thread. The Thread will not lose any locks it holds
* during this time. There are no guarantees which thread will be
* next to run, and it could even be this one, but most VMs will choose
* the highest priority thread that has been waiting longest.
*/
static native void yield(); /**
* Suspend the current Thread's execution for the specified amount of
* time. The Thread will not lose any locks it has during this time. There
* are no guarantees which thread will be next to run, but most VMs will
* choose the highest priority thread that has been waiting longest.
*
* <p>Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do
* not offer that fine a grain of timing resolution. Besides, there is
* no guarantee that this thread can start up immediately when time expires,
* because some other thread may be active. So don't expect real-time
* performance.
*
* @param ms the number of milliseconds to sleep.
* @param ns the number of extra nanoseconds to sleep (0-999999)
* @throws InterruptedException if the Thread is (or was) interrupted;
* it's <i>interrupted status</i> will be cleared
*/
static void sleep(long ms, int ns) throws InterruptedException
{
// Note: JDK treats a zero length sleep is like Thread.yield(),
// without checking the interrupted status of the thread.
// It's unclear if this is a bug in the implementation or the spec.
// See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6213203
if (ms == 0 && ns == 0)
{
if (Thread.interrupted())
throw new InterruptedException();
return;
} // Compute end time, but don't overflow
long now = System.currentTimeMillis();
long end = now + ms;
if (end < now)
end = Long.MAX_VALUE; // A VM is allowed to return from wait() without notify() having been
// called, so we loop to handle possible spurious wakeups.
VMThread vt = Thread.currentThread().vmThread;
synchronized (vt)
{
while (true)
{
vt.wait(ms, ns);
now = System.currentTimeMillis();
if (now >= end)
break;
ms = end - now;
ns = 0;
}
}
} /**
* Determine whether the current Thread has been interrupted, and clear
* the <i>interrupted status</i> in the process.
*
* @return whether the current Thread has been interrupted
*/
static native boolean interrupted(); /**
* Checks whether the current thread holds the monitor on a given object.
* This allows you to do <code>assert Thread.holdsLock(obj)</code>.
*
* @param obj the object to check
* @return true if the current thread is currently synchronized on obj
* @throws NullPointerException if obj is null
*/
static boolean holdsLock(Object obj)
{
/* Use obj.notify to check if the current thread holds
* the monitor of the object.
* If it doesn't, notify will throw an exception.
*/
try
{
obj.notify();
// okay, current thread holds lock
return true;
}
catch (IllegalMonitorStateException e)
{
// it doesn't hold the lock
return false;
}
}

http://docjar.com/docs/api/java/lang/package-index.html

  1. 利用对象,可将一个程序分割成相互独立的区域。我们通常也需要将一个程序转换成多个独立运行的子任务。象这样的每个子任务都叫作一个“线程”(Thread)。编写程序时,可将每个线程都想象成独立运行,而且都有自己的专用CPU。一些基础机制实际会为我们自动分割CPU的时间。
  2. “进程 process”是指一种“自包容” self-contained的运行程序,有自己的地址空间。“多任务”操作系统能同时运行多个进程(程序)——但实际是由于CPU分时机制的作用,使每个进程都能循环获得自己的CPU时间片。但由于轮换速度非常快,使得所有程序好象是在“同时”运行一样。“线程”是进程内部单一的一个顺序控制流。因此,一个进程可能容纳了多个同时执行的线程。
  3. 事实上,多线程最主要的一个用途就是构建一个“反应灵敏”的用户界面 Graphical User Interface。Fast response on GUI.
  4. sleep()必须同一个Thread(线程)对象关联到一起,而且似乎每个应用程序都有部分线程同它关联(事实上,Java本身就是建立在线程基础上的,肯定有一些线程会伴随我们写的应用一起运行)。所以无论我们是否明确使用了线程,都可利用Thread.currentThread()产生由程序使用的当前线程,然后为那个线程调用sleep()。注意,Thread.currentThread()是Thread类的一个静态方法。
  5. 为创建一个线程,最简单的方法就是从Thread类继承。这个类包含了创建和运行线程所需的一切东西。Thread最重要的方法是run()。但为了使用run(),必须对其进行过载或者覆盖,使其能充分按自己的吩咐行事。因此,run()属于那些会与程序中的其他线程“并发”或“同时”执行的代码。
  6. run()方法几乎肯定含有某种形式的循环 loop (While)——它们会一直持续到线程不再需要为止。因此,我们必须规定特定的条件,以便中断并退出这个循环(或者在上述的例子中,简单地从run()返回即可。run()通常采用一种无限循环infinite loop的形式。也就是说,通过阻止外部发出对线程的stop()或者destroy()调用,它会永远运行下去(直到程序完成)。
  7. Thread包含了一个特殊的方法,叫作start(),它的作用是对线程进行特殊的初始化,然后调用run()。所以整个步骤包括:调用构建器来构建对象,然后用start()配置线程,再调用run()。如果不调用start()——如果适当的话 if proper,可在构建器那样做——线程便永远不会启动。
  8. 亦可看出线程并不是按它们创建时的顺序运行的。事实上,CPU处理一个现有线程集的顺序是不确定的——除非我们亲自介入,并用Thread的setPriority()方法调整它们的优先级。priority
  9. 这个接口叫作Runnable (interface),其中包含了与Thread一致的基本方法。事实上,Thread也实现了Runnable,它只指出有一个run()方法。对合并后的程序/线程来说,它的用法不是十分明确。当我们启动程序时,会创建一个Runnable(可运行的)对象,但不会自行启动线程。线程的启动必须明确进行。
  10. Runnable接口最大的一个优点是所有东西都从属于相同的类。若需访问什么东西,只需简单地访问它即可,不需要涉及一个独立的对象。但为这种便利也是要付出代价的——只可为那个特定的对象运行单独一个线程(尽管可创建那种类型的多个对象,或者在不同的类里创建其他对象)。注意Runnable接口本身并不是造成这一限制的罪魁祸首。它是由于Runnable与我们的主类合并造成的,因为每个应用只能主类的一个对象。
  11. “Daemon”线程的作用是在程序的运行期间于后台提供一种“常规”服务,但它并不属于程序的一个基本部分。因此,一旦所有非Daemon线程完成,程序也会中止运行。相反,假若有任何非Daemon线程仍在运行(比如还有一个正在运行main()的线程),则程序的运行不会中止。通过调用isDaemon(),可调查一个线程是不是一个Daemon,而且能用setDaemon()打开或者关闭一个线程的Daemon状态。如果是一个Daemon线程,那么它创建的任何线程也会自动具备Daemon属性。
  12. 可将单线程程序想象成一种孤立的实体,它能遍历我们的问题空间,而且一次只能做一件事情。由于只有一个实体,所以永远不必担心会有两个实体同时试图使用相同的资源,就象两个人同时都想停到一个车位,同时都想通过一扇门,甚至同时发话。进入多线程环境后,它们则再也不是孤立的。可能会有两个甚至更多的线程试图同时同一个有限的资源。必须对这种潜在资源冲突进行预防,否则就可能发生两个线程同时访问一个银行帐号,打印到同一台计算机,以及对同一个值进行调整等等。
  13. 为防止出现这样的冲突,只需在线程使用一个资源时为其加锁即可。访问资源的第一个线程会其加上锁以后,其他线程便不能再使用那个资源,除非被解锁。如果车子的前座是有限的资源,高喊“这是我的!”的孩子会主张把它锁起来。
  14. 对一种特殊的资源——对象中的内存——Java提供了内建的机制来防止它们的冲突。由于我们通常将数据元素设为从属于private(私有)类,然后只通过方法访问那些内存,所以只需将一个特定的方法设为synchronized(同步的),便可有效地防止冲突。在任何时刻,只可有一个线程调用特定对象的一个synchronized方法(尽管那个线程可以调用多个对象的同步方法)。下面列出简单的synchronized方法:
    synchronized void f() { /* ... */ } for one object of Class
  15. 每个对象都包含了一把锁(也叫作“监视器”),它自动成为对象的一部分(不必为此写任何特殊的代码)。调用任何synchronized方法时,对象就会被锁定,不可再调用那个对象的其他任何synchronized方法,除非第一个方法完成了自己的工作,并解除锁定。
  16. 每个类也有自己的一把锁(作为类的Class对象的一部分),所以synchronized static (for all object of Class)法可在一个类的范围内被相互间锁定起来,防止与static数据的接触。注意如果想保护其他某些资源不被多个线程同时访问,可以强制通过synchronized方访问那些资源。
  17. 如果只同步其中的一个方法,那么另一个就可以自由忽视对象的锁定,并可无碍地调用。所以必须记住一个重要的规则:对于访问某个关键共享资源的所有方法,都必须把它们设为synchronized,否则就不能正常地工作。
  18. If the function has the resource which is
    used in another synchronized function, it shall be defined as synchronized
    function.
  19. 由于要为同样的数据编写两个方法,所以无论如何都不会给人留下效率很高的印象。看来似乎更好的一种做法是将所有方法都设为自动同步,并完全消除synchronized关键字(当然,含有synchronized run()的例子显示出这样做是很不通的)。但它也揭示出获取一把锁并非一种“廉价”方案——为一次方法调用付出的代价(进入和退出方法,不执行方法主体)至少要累加到四倍,而且根据我们的具体现方案,这一代价还有可能变得更高。所以假如已知一个方法不会造成冲突,最明智的做法便是撤消其中的synchronized关键字。
  20. 一个线程可以有四种状态:
    (1) 新(New):线程对象已经创建,但尚未启动,所以不可运行。
    (2) 可运行(Runnable):意味着一旦时间分片机制有空闲的CPU周期提供给一个线程,那个线程便可立即开始运行。因此,线程可能在、也可能不在运行当中,但一旦条件许可,没有什么能阻止它的运行——它既没有“死”掉,也未被“堵塞”。
    (3) 死(Dead):从自己的run()方法中返回后,一个线程便已“死”掉。亦可调用stop()令其死掉,但会产生一个违例——属于Error的一个子类(也就是说,我们通常不捕获它)。记住一个违例的“掷”出应当是一个特殊事件,而不是正常程序运行的一部分。所以不建议你使用stop()(在Java 1.2则是坚决反对)。另外还有一个destroy()方法(它永远不会实现),应该尽可能地避免调用它,因为它非常武断,根本不会解除对象的锁定。
    (4) 堵塞(Blocked):线程可以运行,但有某种东西阻碍了它。若线程处于堵塞状态,调度机制可以简单地跳过它,不给它分配任何CPU时间。除非线程再次进入“可运行”状态,否则不会采取任何操作。
  21. 堵塞状态是前述四种状态中最有趣的,值得我们作进一步的探讨。线程被堵塞可能是由下述五方面的原因造成的:
    (1) 调用sleep(毫秒数),使线程进入“睡眠”状态。在规定的时间内,这个线程是不会运行的。
    (2) 用suspend()暂停了线程的执行。除非线程收到resume()消息,否则不会返回“可运行”状态。
    (3) 用wait()暂停了线程的执行。除非线程收到notify()或者notifyAll()消息,否则不会变成“可运行”(是的,这看起来同原因2非常相象,但有一个明显的区别是我们马上要揭示的)。
    (4) 线程正在等候一些IO(输入输出)操作完成。
    (5) 线程试图调用另一个对象的“同步”方法synchronized
    function,但那个对象处于锁定状态,暂时无法使用。
  22. 这是由于wait()在挂起内部调用的方法时,会解除对象的锁定。
  23. 若一个数据流必须等候一些IO活动,便会自动进入“堵塞”状态。在本例下面列出的部分中,有两个类协同通用的Reader以及Writer对象工作(使用Java 1.1的流)。但在测试模型中,会设置一个管道化的数据流,使两个线程相互间能安全地传递数据(这正是使用管道流的目的)。Sender将数据置入Writer,并“睡眠”随机长短的时间。然而,Receiver本身并没有包括sleep(),suspend()或者wait()方法。但在执行read()的时候,如果没有数据存在,它会自动进入“堵塞”状态。
  24. 由于线程可能进入堵塞状态,而且由于对象可能拥有“同步”方法——除非同步锁定被解除,否则线程不能访问那个对象——所以一个线程完全可能等候另一个对象,而另一个对象又在等候下一个对象,以此类推。这个“等候”链最可怕的情形就是进入封闭状态——最后那个对象等候的是第一个对象!此时,所有线程都会陷入无休止的相互等待状态,大家都动弹不得。我们将这种情况称为“死锁”。Dead lock
  25. 为减少出现死锁的可能,Java 1.2作出的一项贡献是“反对”使用Thread的stop(),suspend(),resume()以及destroy()方法。之所以反对使用stop(),是因为它不安全。它会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态(“被破坏”),那么其他线程能在那种状态下检查和修改它们。结果便造成了一种微妙的局面,我们很难检查出真正的问题所在。所以应尽量避免使用stop(),应该采用Blocking.java那样的方法,用一个标志告诉线程什么时候通过退出自己的run()方法来中止自己的执行。
  26. 线程的优先级(Priority)告诉调试程序该线程的重要程度有多大。如果有大量线程都被堵塞,都在等候运行,调试程序会首先运行具有最高优先级的那个线程。然而,这并不表示优先级较低的线程不会运行(换言之,不会因为存在优先级而导致死锁)。若线程的优先级较低,只不过表示它被准许运行的机会小一些而已。可用getPriority()方法读取一个线程的优先级,并用setPriority()改变它。
  27. “线程组中的线程可以修改组内的其他线程,包括那些位于分层结构最深处的。一个线程不能修改位于自己所在组或者下属组之外的任何线程”
  28. 所有线程都隶属于一个线程组。那可以是一个默认线程组,亦可是一个创建线程时明确指定的组。在创建之初,线程被限制到一个组里,而且不能改变到一个不同的组。每个应用都至少有一个线程从属于系统线程组。若创建多个线程而不指定一个组,它们就会自动归属于系统线程组。线程组也必须从属于其他线程组。必须在构建器里指定新线程组从属于哪个线程组。若在创建一个线程组的时候没有指定它的归属,则同样会自动成为系统线程组的一名属下。因此,一个应用程序中的所有线程组最终都会将系统线程组作为自己的“父”。
  29. 当然,如果必须从一个类继承,而且想使类具有线程处理能力,则Runnable是一种正确的方案。
  30. 如果在一个多线程的程序中遇到了性能上的问题,那么现在有许多因素需要检查:
    (1) 对sleep,yield()以及/或者wait()的调用足够多吗?
    (2) sleep()的调用时间足够长吗?
    (3) 运行的线程数是不是太多?
    (4) 试过不同的平台和JVM吗?
    象这样的一些问题是造成多线程应用程序的编制成为一种“技术活”的原因之一。
  31. 何时使用多线程技术,以及何时避免用它,这是我们需要掌握的重要课题。骼它的主要目的是对大量任务进行有序的管理。通过多个任务的混合使用,可以更有效地利用计算机资源,或者对用户来说显得更方便。资源均衡的经典问题是在IO等候期间如何利用CPU。至于用户方面的方便性,最经典的问题就是如何在一个长时间的下载过程中监视并灵敏地反应一个“停止”(stop)按钮的按下。
    多线程的主要缺点包括:
    (1) 等候使用共享资源时造成程序的运行速度变慢。
    (2) 对线程进行管理要求的额外CPU开销。
    (3) 复杂程度无意义的加大,比如用独立的线程来更新数组内每个元素的愚蠢主意。
    (4) 漫长的等待、浪费精力的资源竞争以及死锁等多线程症状。
  32. 线程另一个优点是它们用“轻度”执行切换(100条指令的顺序)取代了“重度”进程场景切换(1000条指令)。由于一个进程内的所有线程共享相同的内存空间,所以“轻度”场景切换只改变程序的执行和本地变量。而在“重度”场景切换时,一个进程的改变要求必须完整地交换内存空间。
  33. 多个线程可能共享同一个资源(比如一个对象里的内存),这是运用线程时面临的最大的一个麻烦。必须保证多个线程不会同时试图读取和修改那个资源。这要求技巧性地运用synchronized(同步)关键字。它是一个有用的工具,但必须真正掌握它,因为假若操作不当,极易出现死锁。
  34. 由于采用了线程“调度”机制,所以通过在run()的主循环中插入对sleep()的调用,一般都可以使自己的程序运行得更快一些。这使它对编程技巧的要求非常高,特别是在更长的延迟似乎反而能提高性能的时候。当然,之所以会出现这种情况,是由于在正在运行的线程准备进入“休眠”状态之前,较短的延迟可能造成“sleep()结束”调度机制的中断。这便强迫调度机制将其中止,并于稍后重新启动,以便它能做完自己的事情,再进入休眠状态。必须多想一想,才能意识到事情真正的麻烦程度.

Programming for thread in Java的更多相关文章

  1. Programming a Spider in Java 源码帖

    Programming a Spider in Java 源码帖 Listing 1: Finding the bad links (CheckLinks.java) import java.awt. ...

  2. Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory

    学习架构探险,从零开始写Java Web框架时,在学习到springAOP时遇到一个异常: "C:\Program Files\Java\jdk1.7.0_40\bin\java" ...

  3. Exception in thread "main" java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter.<init>(I)V

    在学习CGlib动态代理时,遇到如下错误: Exception in thread "main" java.lang.NoSuchMethodError: org.objectwe ...

  4. GUI学习中错误Exception in thread "main" java.lang.NullPointerException

    运行时出现错误:Exception in thread "main" java.lang.NullPointerException 该问题多半是由于用到的某个对象只进行了声明,而没 ...

  5. 执行打的maven jar包时出现“Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes”

    Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for ...

  6. Exception in thread "main" java.lang.ExceptionInInitializerError

    Exception in thread "main" java.lang.ExceptionInInitializerErrorCaused by: java.util.Missi ...

  7. 编译运行java程序出现Exception in thread "main" java.lang.UnsupportedClassVersionError: M : Unsupported major.minor version 51.0

    用javac编译了一个M.java文件, 然后用java M执行,可是出现了下面这个错误. Exception in thread "main" java.lang.Unsuppo ...

  8. dom4j使用xpath报异常 Exception in thread "main" java.lang.NoClassDefFoundError: org/jaxen/NamespaceContext

    Exception in thread "main" java.lang.NoClassDefFoundError: org/jaxen/NamespaceContext      ...

  9. Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1

    场景:eclipse中编写java中用到数组 问题: 程序不报错但是运行过程中 终止,显示字样 “ Exception in thread "main" java.lang.Arr ...

随机推荐

  1. P3380 【模板】二逼平衡树(树套树) 线段树套平衡树

    \(\color{#0066ff}{ 题目描述 }\) 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上 ...

  2. 【三支火把】--- 关于BIOS&UEFI查阅资料网站总结

    UEFI和BIOS的水太深,网上能找到的资料是那么的少,各个组织之间互有交叉,难弄的很,总结了下常用的BIOS资料网站,仅供参考,如果遗漏之处,请指出,博主将继续完善补充……

  3. springboot整合activemq(三)配置文件

    application.properties文件配置: #服务端口,8080被另一服务占用server.port=9090spring.activemq.broker-url=tcp://127.0. ...

  4. 2017年6月15日 由一个freemarker出错引发的感想

    今天想要实现一个功能,想要实现遍历多个checkbox的功能.想出一个解决方法用了30秒钟,将包含的键值put进map中,前台根据map[key]??判断是否具有该值,乍一看这个方法很好,可是实际上问 ...

  5. js 弹性菜单

    <!doctype html> <html> <head> <meta http-equiv="Content-Type" content ...

  6. Nmap工具使用

    Nmap是一款网络扫描和主机检测的非常有用的工具. Nmap是不局限于仅仅收集信息和枚举,同时可以用来作为一个漏洞探测器或安全扫描器.它可以适用于winodws,linux,mac等操作系统.Nmap ...

  7. spark on yarn,cluster模式时,执行spark-submit命令后命令行日志和YARN AM日志

    [root@linux-node1 bin]# ./spark-submit \> --class com.kou.List2Hive \> --master yarn \> --d ...

  8. gitee 搭建自己的代码仓库

    git是什么? 还是科普一下吧:Git是一个开源的分布式版本控制系统,可以有效.高速的处理从很小到非常大的项目版本管理(来自我大百度) 现在越来越多的公司已经使用git来进行项目的版本管理,,使用起来 ...

  9. tencent intern learning

    gslb全局负载均衡   (负载均衡的问题就是某些session保存在某台服务器中,这个用户就只能用那台服务器服务了) jwt vs 传统cookies & session  (jwt类似于公 ...

  10. maya卸载不干净

    AUTODESK系列软件着实令人头疼,安装失败之后不能完全卸载!!!(比如maya,cad,3dsmax等).有时手动删除注册表重装之后还是会出现各种问题,每个版本的C++Runtime和.NET f ...