/* * 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. */ package java.lang; import dalvik.system.VMStack; import java.security.AccessController; import java.util.Map; import java.util.HashMap; import org.apache.harmony.security.fortress.SecurityUtils; /** * 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 * * @since Android 1.0 */ 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. * * @since Android 1.0 */ 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. * * @since Android 1.0 */ public final static int MAX_PRIORITY = 10; /** * The minimum priority value allowed for a thread. * * @since Android 1.0 */ public final static int MIN_PRIORITY = 1; /** * The normal (default) priority value assigned to threads. * * @since Android 1.0 */ public final static 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; /** * Holds the interrupt action for this Thread, if any. * <p> * This is required internally by NIO, so even if it looks like it's * useless, don't delete it! */ private Runnable interruptAction; /** * 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; /** * 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 * * @since Android 1.0 */ 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 * * @since Android 1.0 */ 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 * * @since Android 1.0 */ 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 * * @since Android 1.0 */ 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 SecurityException * if <code>group.checkAccess()</code> fails with a * SecurityException * @throws IllegalThreadStateException * if <code>group.destroy()</code> has already been done * @see java.lang.ThreadGroup * @see java.lang.Runnable * @see java.lang.SecurityException * @see java.lang.SecurityManager * * @since Android 1.0 */ 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 SecurityException * if <code>group.checkAccess()</code> fails with a * SecurityException * @throws IllegalThreadStateException * if <code>group.destroy()</code> has already been done * @see java.lang.ThreadGroup * @see java.lang.Runnable * @see java.lang.SecurityException * @see java.lang.SecurityManager * * @since Android 1.0 */ 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 SecurityException * if <code>group.checkAccess()</code> fails with a * SecurityException * @throws IllegalThreadStateException * if <code>group.destroy()</code> has already been done * @see java.lang.ThreadGroup * @see java.lang.Runnable * @see java.lang.SecurityException * @see java.lang.SecurityManager * * @since Android 1.0 */ 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 SecurityException * if <code>group.checkAccess()</code> fails with a * SecurityException * @throws IllegalThreadStateException * if <code>group.destroy()</code> has already been done * @see java.lang.ThreadGroup * @see java.lang.Runnable * @see java.lang.SecurityException * @see java.lang.SecurityManager * * @since Android 1.0 */ 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 SecurityException if <code>group.checkAccess()</code> fails * with a SecurityException * @throws IllegalThreadStateException if <code>group.destroy()</code> has * already been done * @see java.lang.ThreadGroup * @see java.lang.Runnable * @see java.lang.SecurityException * @see java.lang.SecurityManager */ private void create(ThreadGroup group, Runnable runnable, String threadName, long stackSize) { SecurityManager smgr = System.getSecurityManager(); if (smgr != null) { if (group == null) { group = smgr.getThreadGroup(); } /* * Freaky security requirement: If the Thread's class is actually * a subclass of Thread and it tries to override either * getContextClassLoader() or setContextClassLoader(), the * SecurityManager has to allow this. */ if (getClass() != Thread.class) { Class[] signature = new Class[] { ClassLoader.class }; try { getClass().getDeclaredMethod("getContextClassLoader", signature); smgr.checkPermission(new RuntimePermission("enableContextClassLoaderOverride")); } catch (NoSuchMethodException ex) { // Ignore. Just interested in the method's existence. } try { getClass().getDeclaredMethod("setContextClassLoader", signature); smgr.checkPermission(new RuntimePermission("enableContextClassLoaderOverride")); } catch (NoSuchMethodException ex) { // Ignore. Just interested in the method's existence. } } } Thread currentThread = Thread.currentThread(); if (group == null) { group = currentThread.getThreadGroup(); } group.checkAccess(); 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); } // store current AccessControlContext as inherited context for this thread SecurityUtils.putContext(this, AccessController.getContext()); // 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 * * @since Android 1.0 */ public static int activeCount() { return currentThread().getThreadGroup().activeCount(); } /** * Is used for operations that require approval from a SecurityManager. If * there's none installed, this method is a no-op. If there's a * SecurityManager installed, {@link SecurityManager#checkAccess(Thread)} is * called for that SecurityManager. * * @throws SecurityException * if a SecurityManager is installed and it does not allow * access to the Thread. * * @see java.lang.SecurityException * @see java.lang.SecurityManager * * @since Android 1.0 */ public final void checkAccess() { // Forwards the message to the SecurityManager (if there's one) passing // the receiver as parameter SecurityManager currentManager = System.getSecurityManager(); if (currentManager != null) { currentManager.checkAccess(this); } } /** * 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. * * @since Android 1.0 */ @Deprecated public int countStackFrames() { return getStackTrace().length; } /** * Returns the Thread of the caller, that is, the current Thread. * * @return the current Thread. * * @since Android 1.0 */ public static Thread currentThread() { return VMThread.currentThread(); } /** * Destroys the receiver without any monitor cleanup. * * @deprecated Not implemented. * * @since Android 1.0 */ @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() * * @since Android 1.0 */ 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 * @throws SecurityException * if the installed SecurityManager fails * {@link SecurityManager#checkAccess(Thread)} * @see java.lang.SecurityException * @see java.lang.SecurityManager * * @since Android 1.0 */ public static int enumerate(Thread[] threads) { Thread thread = Thread.currentThread(); thread.checkAccess(); return thread.getThreadGroup().enumerate(threads); } /** * <p> * Returns the stack traces of all the currently live threads and puts them * into the given map. * </p> * * @return A Map of current Threads to StackTraceElement arrays. * @throws SecurityException * if the current SecurityManager fails the * {@link SecurityManager#checkPermission(java.security.Permission)} * call. * * @since Android 1.0 */ public static Map<Thread, StackTraceElement[]> getAllStackTraces() { SecurityManager securityManager = System.getSecurityManager(); if (securityManager != null) { securityManager.checkPermission(new RuntimePermission("getStackTrace")); securityManager.checkPermission(new RuntimePermission("modifyThreadGroup")); } 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. * <p> * If the conditions * <ol> * <li>there is a security manager * <li>the caller's class loader is not null * <li>the caller's class loader is not the same as the requested * context class loader and not an ancestor thereof * </ol> * are satisfied, a security check for * <code>RuntimePermission("getClassLoader")</code> is performed first. * * @return ClassLoader The context ClassLoader * @see java.lang.ClassLoader * @see #getContextClassLoader() * * @throws SecurityException * if the aforementioned security check fails. * * @since Android 1.0 */ public ClassLoader getContextClassLoader() { // First, if the conditions // 1) there is a security manager // 2) the caller's class loader is not null // 3) the caller's class loader is not the same as the context // class loader and not an ancestor thereof // are satisfied we should perform a security check. SecurityManager sm = System.getSecurityManager(); if (sm != null) { ClassLoader calling = VMStack.getCallingClassLoader(); if (calling != null && !calling.isAncestorOf(contextClassLoader)) { sm.checkPermission(new RuntimePermission("getClassLoader")); } } 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. * * @since Android 1.0 */ 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. * * @since Android 1.0 */ public long getId() { return id; } /** * Returns the name of the Thread. * * @return the Thread's name * * @since Android 1.0 */ public final String getName() { return name; } /** * Returns the priority of the Thread. * * @return the Thread's priority * @see Thread#setPriority * * @since Android 1.0 */ public final int getPriority() { return priority; } /** * Returns the a stack trace representing the current execution state of * this Thread. * <p> * The <code>RuntimePermission("getStackTrace")</code> is checked before * returning a result. * </p> * * @return an array of StackTraceElements. * @throws SecurityException * if the current SecurityManager fails the * {@link SecurityManager#checkPermission(java.security.Permission)} * call. * * @since Android 1.0 */ public StackTraceElement[] getStackTrace() { SecurityManager securityManager = System.getSecurityManager(); if (securityManager != null) { securityManager.checkPermission(new RuntimePermission("getStackTrace")); } StackTraceElement ste[] = VMStack.getThreadStackTrace(this); return ste != null ? ste : new StackTraceElement[0]; } /** * Returns the current state of the Thread. This method is useful for * monitoring purposes. * * @return a {@link State} value. * * @since Android 1.0 */ 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 * * @since Android 1.0 */ 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}. * * @since Android 1.0 */ public UncaughtExceptionHandler getUncaughtExceptionHandler() { if (uncaughtHandler != null) return uncaughtHandler; else return group; // ThreadGroup is instance of UEH } /** * Posts an interrupt request to this {@code Thread}. Unless the caller is * the {@link #currentThread()}, the method {@code checkAccess()} is called * for the installed {@code SecurityManager}, if any. This may result in a * {@code SecurityException} being thrown. The further 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> * * @throws SecurityException * if <code>checkAccess()</code> fails with a SecurityException * @see java.lang.SecurityException * @see java.lang.SecurityManager * @see Thread#interrupted * @see Thread#isInterrupted * * @since Android 1.0 */ public void interrupt() { checkAccess(); if (interruptAction != null) { interruptAction.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 * * @since Android 1.0 */ 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 lifeness of the Thread * @see Thread#start * * @since Android 1.0 */ 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 * * @since Android 1.0 */ 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 * * @since Android 1.0 */ 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 * * @since Android 1.0 */ 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 * * @since Android 1.0 */ 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 * * @since Android 1.0 */ 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); } } } /** * Resumes a suspended Thread. This is a no-op if the receiver was never * suspended, or suspended and already resumed. If the receiver is * suspended, however, makes it resume to the point where it was when it was * suspended. * * @throws SecurityException * if <code>checkAccess()</code> fails with a SecurityException * @see Thread#suspend() * @deprecated Used with deprecated method {@link Thread#suspend} * * @since Android 1.0 */ @Deprecated public final void resume() { checkAccess(); VMThread vmt = this.vmThread; if (vmt != null) { vmt.resume(); } } /** * Calls the <code>run()</code> method of the Runnable object the receiver * holds. If no Runnable is set, does nothing. * * @see Thread#start * * @since Android 1.0 */ public void run() { if (target != null) { target.run(); } } /** * Set the context ClassLoader for the receiver. * <p> * The <code>RuntimePermission("setContextClassLoader")</code> * is checked prior to setting the handler. * </p> * * @param cl The context ClassLoader * @throws SecurityException if the current SecurityManager fails the * checkPermission call. * @see java.lang.ClassLoader * @see #getContextClassLoader() * * @since Android 1.0 */ public void setContextClassLoader(ClassLoader cl) { SecurityManager securityManager = System.getSecurityManager(); if (securityManager != null) { securityManager.checkPermission(new RuntimePermission("setContextClassLoader")); } 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 * @throws SecurityException * if <code>checkAccess()</code> fails with a SecurityException * @see Thread#isDaemon * * @since Android 1.0 */ public final void setDaemon(boolean isDaemon) { checkAccess(); if (hasBeenStarted) { throw new IllegalThreadStateException("Thread already started."); // TODO Externalize? } if (vmThread == null) { daemon = isDaemon; } } /** * <p> * Sets the default uncaught exception handler. This handler is invoked in * case any Thread dies due to an unhandled exception. * </p> * <p> * The <code>RuntimePermission("setDefaultUncaughtExceptionHandler")</code> * is checked prior to setting the handler. * </p> * * @param handler * The handler to set or <code>null</code>. * @throws SecurityException * if the current SecurityManager fails the checkPermission * call. * * @since Android 1.0 */ public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler) { SecurityManager securityManager = System.getSecurityManager(); if (securityManager != null) { securityManager.checkPermission(new RuntimePermission ("setDefaultUncaughtExceptionHandler")); } Thread.defaultUncaughtHandler = handler; } /** * Set the action to be executed when interruption, which is probably be * used to implement the interruptible channel. The action is null by * default. And if this method is invoked by passing in a non-null value, * this action's run() method will be invoked in <code>interrupt()</code>. * <p> * This is required internally by NIO, so even if it looks like it's * useless, don't delete it! * * @param action the action to be executed when interruption */ @SuppressWarnings("unused") private void setInterruptAction(Runnable action) { this.interruptAction = action; } /** * Sets the name of the Thread. * * @param threadName the new name for the Thread * @throws SecurityException if <code>checkAccess()</code> fails with a * SecurityException * @see Thread#getName * * @since Android 1.0 */ public final void setName(String threadName) { if (threadName == null) { throw new NullPointerException(); } checkAccess(); 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 SecurityException * if <code>checkAccess()</code> fails with a SecurityException * @throws IllegalArgumentException * if the new priority is greater than Thread.MAX_PRIORITY or * less than Thread.MIN_PRIORITY * @see Thread#getPriority * * @since Android 1.0 */ public final void setPriority(int priority) { checkAccess(); if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) { throw new IllegalArgumentException("Prioritiy 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>. * @throws SecurityException * if the current SecurityManager fails the checkAccess call. * * @since Android 1.0 */ public void setUncaughtExceptionHandler(UncaughtExceptionHandler handler) { checkAccess(); 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() * * @since Android 1.0 */ 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() * * @since Android 1.0 */ 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 * * @since Android 1.0 */ 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. * * @throws SecurityException if <code>checkAccess()</code> fails with a * SecurityException * @deprecated because stopping a thread in this manner is unsafe and can * leave your application and the VM in an unpredictable state. * * @since Android 1.0 */ @Deprecated public final void stop() { stop(new ThreadDeath()); } /** * Requests the receiver Thread to stop and throw the * <code>throwable()</code>. The Thread is resumed if it was suspended * and awakened if it was sleeping, so that it can proceed to throw the * <code>throwable()</code>. * * @param throwable Throwable object to be thrown by the Thread * @throws SecurityException if <code>checkAccess()</code> fails with a * SecurityException * @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. * * @since Android 1.0 */ @Deprecated public final synchronized void stop(Throwable throwable) { SecurityManager securityManager = System.getSecurityManager(); if (securityManager != null) { securityManager.checkAccess(this); if (Thread.currentThread() != this) { securityManager.checkPermission(new RuntimePermission("stopThread")); } } if (throwable == null) { throw new NullPointerException(); } VMThread vmt = this.vmThread; if (vmt != null) { vmt.stop(throwable); } } /** * Suspends this Thread. This is a no-op if the receiver is suspended. If * the receiver <code>isAlive()</code> however, suspended it until <code> * resume()</code> is sent to it. Suspend requests are not queued, which * means that N requests are equivalent to just one - only one resume * request is needed in this case. * * @throws SecurityException * if <code>checkAccess()</code> fails with a SecurityException * @see Thread#resume() * @deprecated May cause deadlocks. * * @since Android 1.0 */ @Deprecated public final void suspend() { checkAccess(); VMThread vmt = this.vmThread; if (vmt != null) { vmt.suspend(); } } /** * 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. * * @since Android 1.0 */ @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. * * @since Android 1.0 */ 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 * * @since Android 1.0 */ 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. * * @since Android 1.0 */ 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 * * @since Android 1.0 */ void uncaughtException(Thread thread, Throwable ex); } /** * Implementation of <code>unpark()</code>. See {@link LangAccessImpl}. */ /*package*/ 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; } } } } /** * Implementation of <code>parkFor()</code>. See {@link LangAccessImpl}. * This method must only be called when <code>this</code> is the current * thread. * * @param nanos number of nanoseconds to park for */ /*package*/ 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"); } } } } /** * Implementation of <code>parkUntil()</code>. See {@link LangAccessImpl}. * This method must only be called when <code>this</code> is the current * thread. * * @param time absolute milliseconds since the epoch to park until */ /*package*/ 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); } } } }