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

java.lang.Thread Maven / Gradle / Ivy

/*
 * 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.
 */
/*
 * 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.
 */
/*
 * Copyright (C) 2012 Trillian Mobile AB
 *
 * 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.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 application
 * has at least one thread running when it is started, the main thread, in the main
 * {@link ThreadGroup}. The runtime keeps its own threads in the system thread
 * group.
 *
 * 

There are two ways to execute code in a new thread. * You can either subclass {@code Thread} and overriding its {@link #run()} method, * or construct a new {@code Thread} and pass a {@link Runnable} to the constructor. * In either case, the {@link #start()} method must be called to actually execute * the new {@code Thread}. * *

Each {@code Thread} has an integer priority that affect how the thread is * scheduled by the OS. A new thread inherits the priority of its parent. * A thread's priority can be set using the {@link #setPriority(int)} method. */ 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; private static long count = 0; private static UncaughtExceptionHandler defaultUncaughtHandler = null; private volatile long threadPtr = 0; private ThreadGroup group = null; /** * Holds the thread's ID. We simply count upwards, so * each Thread has a unique ID. */ private long id = 0; private String name = null; private long stackSize; private boolean daemon = false; private int priority = NORM_PRIORITY; private Runnable target = null; /** Callbacks to run on interruption. */ private final List interruptActions = new ArrayList(); private ClassLoader contextClassLoader = null; private UncaughtExceptionHandler uncaughtHandler = null; boolean started = false; /** * Normal thread local values. */ ThreadLocal.Values localValues; /** * Inheritable thread local values. */ ThreadLocal.Values inheritableValues; /** the park state of the thread */ private int parkState = ParkState.UNPARKED; /** The synchronization object responsible for this thread parking. */ private Object parkBlocker; /** The object used to implement join() and parking. */ private Object lock = new Object(); /** * 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 run 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 run 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("threadName == null"); } 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("threadName == null"); } 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 run will be * executed by the new {@code Thread} * @throws IllegalThreadStateException * if group.destroy() 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 run will be * executed by the new {@code Thread} * @param threadName * the name for the {@code Thread} being created * @throws IllegalThreadStateException * if group.destroy() 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("threadName == null"); } 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 group.destroy() has already been done * @see java.lang.ThreadGroup * @see java.lang.Runnable */ public Thread(ThreadGroup group, String threadName) { if (threadName == null) { throw new NullPointerException("threadName == null"); } 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 run 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 group.destroy() 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("threadName == null"); } 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(long threadPtr, String name, ThreadGroup group, boolean daemon) { // NOTE: Must set threadPtr before the synchronized block below this.threadPtr = threadPtr; this.daemon = daemon; this.group = group == null ? ThreadGroup.mMain : group; synchronized (Thread.class) { id = ++count; } this.name = name == null ? "Thread-" + this.id : name; this.priority = NORM_PRIORITY; this.started = true; 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 run will * be executed by the new Thread * @param threadName Name for the Thread being created * @param stackSize Platform dependent stack size * @throws IllegalThreadStateException if group.destroy() 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 native static Thread currentThread(); /** * Throws {@code UnsupportedOperationException}. * @deprecated Not implemented. */ @Deprecated public void destroy() { throw new UnsupportedOperationException(); } /** * 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(); } final void printStackTrace(Throwable t) { System.err.print("Exception in thread \""); System.err.print(name); System.err.print("\" "); t.printStackTrace(System.err); System.err.flush(); } /** * Copies an array with all Threads which are in the same ThreadGroup as the * receiver - and subgroups - into the array threads 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 getAllStackTraces() { Map map = new HashMap(); // 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.mMain.activeCount(); Thread[] threads = new Thread[count + count / 2]; // Enumerate the threads and collect the stacktraces. count = ThreadGroup.mMain.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 null if * none exists. */ public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() { return defaultUncaughtHandler; } /** * Returns the thread's identifier. The ID is a positive long * 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. */ public final String getName() { return name; } /** * Returns the priority of the Thread. */ public final int getPriority() { return priority; } /** * Returns an array of {@link StackTraceElement} representing the current thread's stack. */ public StackTraceElement[] getStackTrace() { if (threadPtr == 0) { return EmptyArray.STACK_TRACE_ELEMENT; } return internalGetStackTrace(this); } private static native StackTraceElement[] internalGetStackTrace(Thread thread); /** * Returns the current state of the Thread. This method is useful for * monitoring purposes. * * @return a {@link State} value. */ public State getState() { if (threadPtr != 0) { int s = internalGetState(this); switch (s) { case 0: return State.TERMINATED; // ZOMBIE case 1: return State.RUNNABLE; // RUNNING case 2: return State.TIMED_WAITING; // TIMED_WAIT case 3: return State.BLOCKED; // MONITOR case 4: return State.WAITING; // WAIT case 5: return State.NEW; // INITIALIZING case 6: return State.NEW; // STARTING case 7: return State.RUNNABLE; // NATIVE case 8: return State.WAITING; // VMWAIT case 9: return State.RUNNABLE; // SUSPENDED } } return started ? State.TERMINATED : State.NEW; } private static native int internalGetState(Thread thread); /** * 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 null 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}: *

    *
  • * {@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}. *
  • * {@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. *
  • * {@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. *
      * * @see Thread#interrupted * @see Thread#isInterrupted */ public void interrupt() { // Interrupt this thread before running actions so that other // threads that observe the interrupt as a result of an action // will see that this thread is in the interrupted state. if (threadPtr != 0) { internalInterrupt(this); } synchronized (interruptActions) { for (int i = interruptActions.size() - 1; i >= 0; i--) { interruptActions.get(i).run(); } } } private static native void internalInterrupt(Thread thread); /** * Returns a boolean indicating whether the current Thread ( * currentThread()) has a pending interrupt request ( * true) or not (false). It also has the side-effect of * clearing the flag. * * @return a boolean indicating the interrupt status * @see Thread#currentThread * @see Thread#interrupt * @see Thread#isInterrupted */ public static boolean interrupted() { return internalInterrupted(); } private static native boolean internalInterrupted(); /** * Returns true if the receiver has already been started and * still runs code (hasn't died yet). Returns false either if * the receiver hasn't been started yet or if it has already started and run * to completion and died. * * @return a boolean indicating the liveness of the Thread * @see Thread#start */ public final boolean isAlive() { return threadPtr != 0; } /** * Tests whether this is a daemon thread. * A daemon thread only runs as long as there are non-daemon threads running. * When the last non-daemon thread ends, the runtime will exit. This is not * normally relevant to applications with a UI. */ public final boolean isDaemon() { return daemon; } /** * Returns a boolean indicating whether the receiver has a * pending interrupt request (true) or not ( * false) * * @return a boolean indicating the interrupt status * @see Thread#interrupt * @see Thread#interrupted */ public boolean isInterrupted() { if (threadPtr != 0) { return internalIsInterrupted(this); } return false; } private static native boolean internalIsInterrupted(Thread thread); /** * Blocks the current Thread (Thread.currentThread()) until * the receiver finishes its execution and dies. * * @throws InterruptedException if interrupt() was called for * the receiver while it was in the join() call * @see Object#notifyAll * @see java.lang.ThreadDeath */ public final void join() throws InterruptedException { if (threadPtr == 0) { return; } synchronized (lock) { while (isAlive()) { lock.wait(); } } } /** * Blocks the current Thread (Thread.currentThread()) 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 interrupt() was called for * the receiver while it was in the join() call * @see Object#notifyAll * @see java.lang.ThreadDeath */ public final void join(long millis) throws InterruptedException { join(millis, 0); } /** * Blocks the current Thread (Thread.currentThread()) 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 interrupt() was called for * the receiver while it was in the join() 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("bad timeout: millis=" + millis + ",nanos=" + nanos); } // 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; } if (threadPtr == 0) { return; } synchronized (lock) { 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) { lock.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}. * @deprecated Only useful in conjunction with deprecated method {@link Thread#suspend}. */ @Deprecated public final void resume() { throw new UnsupportedOperationException(); } /** * Calls the run() 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; } /** * Marks this thread as a daemon thread. * A daemon thread only runs as long as there are non-daemon threads running. * When the last non-daemon thread ends, the runtime will exit. This is not * normally relevant to applications with a UI. * @throws IllegalThreadStateException - if this thread has already started. */ public final void setDaemon(boolean isDaemon) { checkNotStarted(); if (threadPtr == 0) { daemon = isDaemon; } } private void checkNotStarted() { if (started) { throw new IllegalThreadStateException("Thread already started"); } } /** * 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. * *

      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("threadName == null"); } name = threadName; if (threadPtr != 0) { /* notify the VM that the thread name has changed */ internalSetName(this, threadName); } } private static native void internalSetName(Thread thread, String threadName); /** * Sets the priority of this thread. If the requested priority is greater than the * parent thread group's {@link java.lang.ThreadGroup#getMaxPriority}, the group's maximum * priority will be used instead. * * @throws IllegalArgumentException - if the new priority is greater than {@link #MAX_PRIORITY} * or less than {@link #MIN_PRIORITY} */ public final void setPriority(int priority) { if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) { throw new IllegalArgumentException("Priority out of range: " + priority); } if (priority > group.getMaxPriority()) { priority = group.getMaxPriority(); } this.priority = priority; if (threadPtr != 0) { internalSetPriority(this, priority); } } private static native void internalSetPriority(Thread thread, int priority); /** *

      * Sets the uncaught exception handler. This handler is invoked in case this * Thread dies due to an unhandled exception. *

      * * @param handler * The handler to set or null. */ 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 interrupt() 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 interrupt() was called for this Thread while * it was sleeping * @see Thread#interrupt() */ public static void sleep(long millis, int nanos) throws InterruptedException { internalSleep(millis, nanos); } private static native void internalSleep(long millis, int nanos) throws InterruptedException; /** * Starts the new Thread of execution. The run() method of * the receiver will be called by the receiver Thread itself (and not the * Thread calling start()). * * @throws IllegalThreadStateException - if this thread has already started. * @see Thread#run */ public synchronized void start() { checkNotStarted(); started = true; internalStart(this); } private static native void internalStart(Thread t); /** * 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 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}. * @deprecated 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}. * @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() { internalYield(); } private static native void internalYield(); /** * 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 internalHoldsLock(object); } private static native boolean internalHoldsLock(Object 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. * *

      See {@link java.util.concurrent.locks.LockSupport} for more * in-depth information of the behavior of this method.

      * * @hide for Unsafe */ public void unpark() { if (threadPtr == 0) { /* * 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 (lock) { 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; lock.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). * *

      See {@link java.util.concurrent.locks.LockSupport} for more * in-depth information of the behavior of this method.

      * *

      This method must only be called when this is the current * thread. * * @param nanos number of nanoseconds to park for or 0 * to park indefinitely * @throws IllegalArgumentException thrown if nanos < 0 * * @hide for Unsafe */ public void parkFor(long nanos) { if (threadPtr == 0) { // Running threads should always have an associated threadPtr. throw new AssertionError(); } synchronized (lock) { 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 { lock.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 * System.currentTimeMillis() 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). * *

      See {@link java.util.concurrent.locks.LockSupport} for more * in-depth information of the behavior of this method.

      * *

      This method must only be called when this 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) { if (threadPtr == 0) { // Running threads should always have an associated threadPtr. throw new AssertionError(); } synchronized (lock) { /* * 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); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy