| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code 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 |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package java.lang; |
| |
| import dalvik.annotation.optimization.FastNative; |
| import java.lang.ref.Reference; |
| import java.lang.ref.ReferenceQueue; |
| import java.lang.ref.WeakReference; |
| import java.security.AccessController; |
| import java.security.AccessControlContext; |
| import java.security.PrivilegedAction; |
| import java.util.Map; |
| import java.util.HashMap; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.ConcurrentMap; |
| import java.util.concurrent.locks.LockSupport; |
| import sun.nio.ch.Interruptible; |
| import sun.reflect.CallerSensitive; |
| import dalvik.system.VMStack; |
| import libcore.util.EmptyArray; |
| |
| |
| /** |
| * A <i>thread</i> is a thread of execution in a program. The Java |
| * Virtual Machine allows an application to have multiple threads of |
| * execution running concurrently. |
| * <p> |
| * Every thread has a priority. Threads with higher priority are |
| * executed in preference to threads with lower priority. Each thread |
| * may or may not also be marked as a daemon. When code running in |
| * some thread creates a new <code>Thread</code> object, the new |
| * thread has its priority initially set equal to the priority of the |
| * creating thread, and is a daemon thread if and only if the |
| * creating thread is a daemon. |
| * <p> |
| * When a Java Virtual Machine starts up, there is usually a single |
| * non-daemon thread (which typically calls the method named |
| * <code>main</code> of some designated class). The Java Virtual |
| * Machine continues to execute threads until either of the following |
| * occurs: |
| * <ul> |
| * <li>The <code>exit</code> method of class <code>Runtime</code> has been |
| * called and the security manager has permitted the exit operation |
| * to take place. |
| * <li>All threads that are not daemon threads have died, either by |
| * returning from the call to the <code>run</code> method or by |
| * throwing an exception that propagates beyond the <code>run</code> |
| * method. |
| * </ul> |
| * <p> |
| * There are two ways to create a new thread of execution. One is to |
| * declare a class to be a subclass of <code>Thread</code>. This |
| * subclass should override the <code>run</code> method of class |
| * <code>Thread</code>. An instance of the subclass can then be |
| * allocated and started. For example, a thread that computes primes |
| * larger than a stated value could be written as follows: |
| * <hr><blockquote><pre> |
| * class PrimeThread extends Thread { |
| * long minPrime; |
| * PrimeThread(long minPrime) { |
| * this.minPrime = minPrime; |
| * } |
| * |
| * public void run() { |
| * // compute primes larger than minPrime |
| * . . . |
| * } |
| * } |
| * </pre></blockquote><hr> |
| * <p> |
| * The following code would then create a thread and start it running: |
| * <blockquote><pre> |
| * PrimeThread p = new PrimeThread(143); |
| * p.start(); |
| * </pre></blockquote> |
| * <p> |
| * The other way to create a thread is to declare a class that |
| * implements the <code>Runnable</code> interface. That class then |
| * implements the <code>run</code> method. An instance of the class can |
| * then be allocated, passed as an argument when creating |
| * <code>Thread</code>, and started. The same example in this other |
| * style looks like the following: |
| * <hr><blockquote><pre> |
| * class PrimeRun implements Runnable { |
| * long minPrime; |
| * PrimeRun(long minPrime) { |
| * this.minPrime = minPrime; |
| * } |
| * |
| * public void run() { |
| * // compute primes larger than minPrime |
| * . . . |
| * } |
| * } |
| * </pre></blockquote><hr> |
| * <p> |
| * The following code would then create a thread and start it running: |
| * <blockquote><pre> |
| * PrimeRun p = new PrimeRun(143); |
| * new Thread(p).start(); |
| * </pre></blockquote> |
| * <p> |
| * Every thread has a name for identification purposes. More than |
| * one thread may have the same name. If a name is not specified when |
| * a thread is created, a new name is generated for it. |
| * <p> |
| * Unless otherwise noted, passing a {@code null} argument to a constructor |
| * or method in this class will cause a {@link NullPointerException} to be |
| * thrown. |
| * |
| * @author unascribed |
| * @see Runnable |
| * @see Runtime#exit(int) |
| * @see #run() |
| * @see #stop() |
| * @since JDK1.0 |
| */ |
| public |
| class Thread implements Runnable { |
| /* Make sure registerNatives is the first thing <clinit> does. */ |
| |
| /** |
| * The synchronization object responsible for this thread's join/sleep/park operations. |
| */ |
| private final Object lock = new Object(); |
| |
| private volatile long nativePeer; |
| |
| boolean started = false; |
| |
| private volatile String name; |
| |
| private int priority; |
| private Thread threadQ; |
| private long eetop; |
| |
| /* Whether or not to single_step this thread. */ |
| private boolean single_step; |
| |
| /* Whether or not the thread is a daemon thread. */ |
| private boolean daemon = false; |
| |
| /* JVM state */ |
| private boolean stillborn = false; |
| |
| /* What will be run. */ |
| private Runnable target; |
| |
| /* The group of this thread */ |
| private ThreadGroup group; |
| |
| /* The context ClassLoader for this thread */ |
| private ClassLoader contextClassLoader; |
| |
| /* The inherited AccessControlContext of this thread */ |
| private AccessControlContext inheritedAccessControlContext; |
| |
| /* For autonumbering anonymous threads. */ |
| private static int threadInitNumber; |
| private static synchronized int nextThreadNum() { |
| return threadInitNumber++; |
| } |
| |
| /* ThreadLocal values pertaining to this thread. This map is maintained |
| * by the ThreadLocal class. */ |
| ThreadLocal.ThreadLocalMap threadLocals = null; |
| |
| /* |
| * InheritableThreadLocal values pertaining to this thread. This map is |
| * maintained by the InheritableThreadLocal class. |
| */ |
| ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; |
| |
| /* |
| * The requested stack size for this thread, or 0 if the creator did |
| * not specify a stack size. It is up to the VM to do whatever it |
| * likes with this number; some VMs will ignore it. |
| */ |
| private long stackSize; |
| |
| /* |
| * JVM-private state that persists after native thread termination. |
| */ |
| private long nativeParkEventPointer; |
| |
| /* |
| * Thread ID |
| */ |
| private long tid; |
| |
| /* For generating thread ID */ |
| private static long threadSeqNumber; |
| |
| /* Java thread status for tools, |
| * initialized to indicate thread 'not yet started' |
| */ |
| |
| private volatile int threadStatus = 0; |
| |
| |
| private static synchronized long nextThreadID() { |
| return ++threadSeqNumber; |
| } |
| |
| /** |
| * The argument supplied to the current call to |
| * java.util.concurrent.locks.LockSupport.park. |
| * Set by (private) java.util.concurrent.locks.LockSupport.setBlocker |
| * Accessed using java.util.concurrent.locks.LockSupport.getBlocker |
| */ |
| volatile Object parkBlocker; |
| |
| /* The object in which this thread is blocked in an interruptible I/O |
| * operation, if any. The blocker's interrupt method should be invoked |
| * after setting this thread's interrupt status. |
| */ |
| private volatile Interruptible blocker; |
| private final Object blockerLock = new Object(); |
| |
| /** |
| * Set the blocker field; invoked via sun.misc.SharedSecrets from java.nio code |
| * |
| * @hide |
| */ |
| public void blockedOn(Interruptible b) { |
| synchronized (blockerLock) { |
| blocker = b; |
| } |
| } |
| |
| /** |
| * The minimum priority that a thread can have. |
| */ |
| public final static int MIN_PRIORITY = 1; |
| |
| /** |
| * The default priority that is assigned to a thread. |
| */ |
| public final static int NORM_PRIORITY = 5; |
| |
| /** |
| * The maximum priority that a thread can have. |
| */ |
| public final static int MAX_PRIORITY = 10; |
| |
| /** |
| * Returns a reference to the currently executing thread object. |
| * |
| * @return the currently executing thread. |
| */ |
| @FastNative |
| public static native Thread currentThread(); |
| |
| /** |
| * A hint to the scheduler that the current thread is willing to yield |
| * its current use of a processor. The scheduler is free to ignore this |
| * hint. |
| * |
| * <p> Yield is a heuristic attempt to improve relative progression |
| * between threads that would otherwise over-utilise a CPU. Its use |
| * should be combined with detailed profiling and benchmarking to |
| * ensure that it actually has the desired effect. |
| * |
| * <p> It is rarely appropriate to use this method. It may be useful |
| * for debugging or testing purposes, where it may help to reproduce |
| * bugs due to race conditions. It may also be useful when designing |
| * concurrency control constructs such as the ones in the |
| * {@link java.util.concurrent.locks} package. |
| */ |
| public static native void yield(); |
| |
| /** |
| * Causes the currently executing thread to sleep (temporarily cease |
| * execution) for the specified number of milliseconds, subject to |
| * the precision and accuracy of system timers and schedulers. The thread |
| * does not lose ownership of any monitors. |
| * |
| * @param millis |
| * the length of time to sleep in milliseconds |
| * |
| * @throws IllegalArgumentException |
| * if the value of {@code millis} is negative |
| * |
| * @throws InterruptedException |
| * if any thread has interrupted the current thread. The |
| * <i>interrupted status</i> of the current thread is |
| * cleared when this exception is thrown. |
| */ |
| public static void sleep(long millis) throws InterruptedException { |
| Thread.sleep(millis, 0); |
| } |
| |
| @FastNative |
| private static native void sleep(Object lock, long millis, int nanos) |
| throws InterruptedException; |
| |
| /** |
| * Causes the currently executing thread to sleep (temporarily cease |
| * execution) for the specified number of milliseconds plus the specified |
| * number of nanoseconds, subject to the precision and accuracy of system |
| * timers and schedulers. The thread does not lose ownership of any |
| * monitors. |
| * |
| * @param millis |
| * the length of time to sleep in milliseconds |
| * |
| * @param nanos |
| * {@code 0-999999} additional nanoseconds to sleep |
| * |
| * @throws IllegalArgumentException |
| * if the value of {@code millis} is negative, or the value of |
| * {@code nanos} is not in the range {@code 0-999999} |
| * |
| * @throws InterruptedException |
| * if any thread has interrupted the current thread. The |
| * <i>interrupted status</i> of the current thread is |
| * cleared when this exception is thrown. |
| */ |
| public static void sleep(long millis, int nanos) |
| throws InterruptedException { |
| if (millis < 0) { |
| throw new IllegalArgumentException("millis < 0: " + millis); |
| } |
| if (nanos < 0) { |
| throw new IllegalArgumentException("nanos < 0: " + nanos); |
| } |
| if (nanos > 999999) { |
| throw new IllegalArgumentException("nanos > 999999: " + nanos); |
| } |
| |
| // The JLS 3rd edition, section 17.9 says: "...sleep for zero |
| // time...need not have observable effects." |
| if (millis == 0 && nanos == 0) { |
| // ...but we still have to handle being interrupted. |
| if (Thread.interrupted()) { |
| throw new InterruptedException(); |
| } |
| return; |
| } |
| |
| long start = System.nanoTime(); |
| long duration = (millis * NANOS_PER_MILLI) + nanos; |
| |
| Object lock = currentThread().lock; |
| |
| // Wait may return early, so loop until sleep duration passes. |
| synchronized (lock) { |
| while (true) { |
| sleep(lock, millis, nanos); |
| |
| long now = System.nanoTime(); |
| long elapsed = now - start; |
| |
| if (elapsed >= duration) { |
| break; |
| } |
| |
| duration -= elapsed; |
| start = now; |
| millis = duration / NANOS_PER_MILLI; |
| nanos = (int) (duration % NANOS_PER_MILLI); |
| } |
| } |
| } |
| |
| /** |
| * Initializes a Thread. |
| * |
| * @param g the Thread group |
| * @param target the object whose run() method gets called |
| * @param name the name of the new Thread |
| * @param stackSize the desired stack size for the new thread, or |
| * zero to indicate that this parameter is to be ignored. |
| */ |
| private void init(ThreadGroup g, Runnable target, String name, long stackSize) { |
| Thread parent = currentThread(); |
| if (g == null) { |
| g = parent.getThreadGroup(); |
| } |
| |
| g.addUnstarted(); |
| this.group = g; |
| |
| this.target = target; |
| this.priority = parent.getPriority(); |
| this.daemon = parent.isDaemon(); |
| setName(name); |
| |
| init2(parent); |
| |
| /* Stash the specified stack size in case the VM cares */ |
| this.stackSize = stackSize; |
| tid = nextThreadID(); |
| } |
| |
| /** |
| * Throws CloneNotSupportedException as a Thread can not be meaningfully |
| * cloned. Construct a new Thread instead. |
| * |
| * @throws CloneNotSupportedException |
| * always |
| */ |
| @Override |
| protected Object clone() throws CloneNotSupportedException { |
| throw new CloneNotSupportedException(); |
| } |
| |
| /** |
| * Allocates a new {@code Thread} object. This constructor has the same |
| * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} |
| * {@code (null, null, gname)}, where {@code gname} is a newly generated |
| * name. Automatically generated names are of the form |
| * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer. |
| */ |
| public Thread() { |
| init(null, null, "Thread-" + nextThreadNum(), 0); |
| } |
| |
| /** |
| * Allocates a new {@code Thread} object. This constructor has the same |
| * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} |
| * {@code (null, target, gname)}, where {@code gname} is a newly generated |
| * name. Automatically generated names are of the form |
| * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer. |
| * |
| * @param target |
| * the object whose {@code run} method is invoked when this thread |
| * is started. If {@code null}, this classes {@code run} method does |
| * nothing. |
| */ |
| public Thread(Runnable target) { |
| init(null, target, "Thread-" + nextThreadNum(), 0); |
| } |
| |
| /** |
| * Allocates a new {@code Thread} object. This constructor has the same |
| * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} |
| * {@code (group, target, gname)} ,where {@code gname} is a newly generated |
| * name. Automatically generated names are of the form |
| * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer. |
| * |
| * @param group |
| * the thread group. If {@code null} and there is a security |
| * manager, the group is determined by {@linkplain |
| * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}. |
| * If there is not a security manager or {@code |
| * SecurityManager.getThreadGroup()} returns {@code null}, the group |
| * is set to the current thread's thread group. |
| * |
| * @param target |
| * the object whose {@code run} method is invoked when this thread |
| * is started. If {@code null}, this thread's run method is invoked. |
| * |
| * @throws SecurityException |
| * if the current thread cannot create a thread in the specified |
| * thread group |
| */ |
| public Thread(ThreadGroup group, Runnable target) { |
| init(group, target, "Thread-" + nextThreadNum(), 0); |
| } |
| |
| /** |
| * Allocates a new {@code Thread} object. This constructor has the same |
| * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} |
| * {@code (null, null, name)}. |
| * |
| * @param name |
| * the name of the new thread |
| */ |
| public Thread(String name) { |
| init(null, null, name, 0); |
| } |
| |
| /** |
| * Allocates a new {@code Thread} object. This constructor has the same |
| * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} |
| * {@code (group, null, name)}. |
| * |
| * @param group |
| * the thread group. If {@code null} and there is a security |
| * manager, the group is determined by {@linkplain |
| * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}. |
| * If there is not a security manager or {@code |
| * SecurityManager.getThreadGroup()} returns {@code null}, the group |
| * is set to the current thread's thread group. |
| * |
| * @param name |
| * the name of the new thread |
| * |
| * @throws SecurityException |
| * if the current thread cannot create a thread in the specified |
| * thread group |
| */ |
| public Thread(ThreadGroup group, String name) { |
| init(group, null, name, 0); |
| } |
| |
| |
| /** @hide */ |
| // Android-added: Private constructor - used by the runtime. |
| Thread(ThreadGroup group, String name, int priority, boolean daemon) { |
| this.group = group; |
| this.group.addUnstarted(); |
| // Must be tolerant of threads without a name. |
| if (name == null) { |
| name = "Thread-" + nextThreadNum(); |
| } |
| |
| // NOTE: Resist the temptation to call setName() here. This constructor is only called |
| // by the runtime to construct peers for threads that have attached via JNI and it's |
| // undesirable to clobber their natively set name. |
| this.name = name; |
| |
| this.priority = priority; |
| this.daemon = daemon; |
| init2(currentThread()); |
| tid = nextThreadID(); |
| } |
| |
| private void init2(Thread parent) { |
| this.contextClassLoader = parent.getContextClassLoader(); |
| this.inheritedAccessControlContext = AccessController.getContext(); |
| if (parent.inheritableThreadLocals != null) { |
| this.inheritableThreadLocals = ThreadLocal.createInheritedMap( |
| parent.inheritableThreadLocals); |
| } |
| } |
| |
| /** |
| * Allocates a new {@code Thread} object. This constructor has the same |
| * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} |
| * {@code (null, target, name)}. |
| * |
| * @param target |
| * the object whose {@code run} method is invoked when this thread |
| * is started. If {@code null}, this thread's run method is invoked. |
| * |
| * @param name |
| * the name of the new thread |
| */ |
| public Thread(Runnable target, String name) { |
| init(null, target, name, 0); |
| } |
| |
| /** |
| * Allocates a new {@code Thread} object so that it has {@code target} |
| * as its run object, has the specified {@code name} as its name, |
| * and belongs to the thread group referred to by {@code group}. |
| * |
| * <p>If there is a security manager, its |
| * {@link SecurityManager#checkAccess(ThreadGroup) checkAccess} |
| * method is invoked with the ThreadGroup as its argument. |
| * |
| * <p>In addition, its {@code checkPermission} method is invoked with |
| * the {@code RuntimePermission("enableContextClassLoaderOverride")} |
| * permission when invoked directly or indirectly by the constructor |
| * of a subclass which overrides the {@code getContextClassLoader} |
| * or {@code setContextClassLoader} methods. |
| * |
| * <p>The priority of the newly created thread is set equal to the |
| * priority of the thread creating it, that is, the currently running |
| * thread. The method {@linkplain #setPriority setPriority} may be |
| * used to change the priority to a new value. |
| * |
| * <p>The newly created thread is initially marked as being a daemon |
| * thread if and only if the thread creating it is currently marked |
| * as a daemon thread. The method {@linkplain #setDaemon setDaemon} |
| * may be used to change whether or not a thread is a daemon. |
| * |
| * @param group |
| * the thread group. If {@code null} and there is a security |
| * manager, the group is determined by {@linkplain |
| * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}. |
| * If there is not a security manager or {@code |
| * SecurityManager.getThreadGroup()} returns {@code null}, the group |
| * is set to the current thread's thread group. |
| * |
| * @param target |
| * the object whose {@code run} method is invoked when this thread |
| * is started. If {@code null}, this thread's run method is invoked. |
| * |
| * @param name |
| * the name of the new thread |
| * |
| * @throws SecurityException |
| * if the current thread cannot create a thread in the specified |
| * thread group or cannot override the context class loader methods. |
| */ |
| public Thread(ThreadGroup group, Runnable target, String name) { |
| init(group, target, name, 0); |
| } |
| |
| /** |
| * Allocates a new {@code Thread} object so that it has {@code target} |
| * as its run object, has the specified {@code name} as its name, |
| * and belongs to the thread group referred to by {@code group}, and has |
| * the specified <i>stack size</i>. |
| * |
| * <p>This constructor is identical to {@link |
| * #Thread(ThreadGroup,Runnable,String)} with the exception of the fact |
| * that it allows the thread stack size to be specified. The stack size |
| * is the approximate number of bytes of address space that the virtual |
| * machine is to allocate for this thread's stack. <b>The effect of the |
| * {@code stackSize} parameter, if any, is highly platform dependent.</b> |
| * |
| * <p>On some platforms, specifying a higher value for the |
| * {@code stackSize} parameter may allow a thread to achieve greater |
| * recursion depth before throwing a {@link StackOverflowError}. |
| * Similarly, specifying a lower value may allow a greater number of |
| * threads to exist concurrently without throwing an {@link |
| * OutOfMemoryError} (or other internal error). The details of |
| * the relationship between the value of the <tt>stackSize</tt> parameter |
| * and the maximum recursion depth and concurrency level are |
| * platform-dependent. <b>On some platforms, the value of the |
| * {@code stackSize} parameter may have no effect whatsoever.</b> |
| * |
| * <p>The virtual machine is free to treat the {@code stackSize} |
| * parameter as a suggestion. If the specified value is unreasonably low |
| * for the platform, the virtual machine may instead use some |
| * platform-specific minimum value; if the specified value is unreasonably |
| * high, the virtual machine may instead use some platform-specific |
| * maximum. Likewise, the virtual machine is free to round the specified |
| * value up or down as it sees fit (or to ignore it completely). |
| * |
| * <p>Specifying a value of zero for the {@code stackSize} parameter will |
| * cause this constructor to behave exactly like the |
| * {@code Thread(ThreadGroup, Runnable, String)} constructor. |
| * |
| * <p><i>Due to the platform-dependent nature of the behavior of this |
| * constructor, extreme care should be exercised in its use. |
| * The thread stack size necessary to perform a given computation will |
| * likely vary from one JRE implementation to another. In light of this |
| * variation, careful tuning of the stack size parameter may be required, |
| * and the tuning may need to be repeated for each JRE implementation on |
| * which an application is to run.</i> |
| * |
| * <p>Implementation note: Java platform implementers are encouraged to |
| * document their implementation's behavior with respect to the |
| * {@code stackSize} parameter. |
| * |
| * |
| * @param group |
| * the thread group. If {@code null} and there is a security |
| * manager, the group is determined by {@linkplain |
| * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}. |
| * If there is not a security manager or {@code |
| * SecurityManager.getThreadGroup()} returns {@code null}, the group |
| * is set to the current thread's thread group. |
| * |
| * @param target |
| * the object whose {@code run} method is invoked when this thread |
| * is started. If {@code null}, this thread's run method is invoked. |
| * |
| * @param name |
| * the name of the new thread |
| * |
| * @param stackSize |
| * the desired stack size for the new thread, or zero to indicate |
| * that this parameter is to be ignored. |
| * |
| * @throws SecurityException |
| * if the current thread cannot create a thread in the specified |
| * thread group |
| * |
| * @since 1.4 |
| */ |
| public Thread(ThreadGroup group, Runnable target, String name, |
| long stackSize) { |
| init(group, target, name, stackSize); |
| } |
| |
| /** |
| * Causes this thread to begin execution; the Java Virtual Machine |
| * calls the <code>run</code> method of this thread. |
| * <p> |
| * The result is that two threads are running concurrently: the |
| * current thread (which returns from the call to the |
| * <code>start</code> method) and the other thread (which executes its |
| * <code>run</code> method). |
| * <p> |
| * It is never legal to start a thread more than once. |
| * In particular, a thread may not be restarted once it has completed |
| * execution. |
| * |
| * @exception IllegalThreadStateException if the thread was already |
| * started. |
| * @see #run() |
| * @see #stop() |
| */ |
| public synchronized void start() { |
| /** |
| * This method is not invoked for the main method thread or "system" |
| * group threads created/set up by the VM. Any new functionality added |
| * to this method in the future may have to also be added to the VM. |
| * |
| * A zero status value corresponds to state "NEW". |
| */ |
| // Android-changed: throw if 'started' is true |
| if (threadStatus != 0 || started) |
| throw new IllegalThreadStateException(); |
| |
| /* Notify the group that this thread is about to be started |
| * so that it can be added to the group's list of threads |
| * and the group's unstarted count can be decremented. */ |
| group.add(this); |
| |
| started = false; |
| try { |
| nativeCreate(this, stackSize, daemon); |
| started = true; |
| } finally { |
| try { |
| if (!started) { |
| group.threadStartFailed(this); |
| } |
| } catch (Throwable ignore) { |
| /* do nothing. If start0 threw a Throwable then |
| it will be passed up the call stack */ |
| } |
| } |
| } |
| |
| private native static void nativeCreate(Thread t, long stackSize, boolean daemon); |
| |
| /** |
| * If this thread was constructed using a separate |
| * <code>Runnable</code> run object, then that |
| * <code>Runnable</code> object's <code>run</code> method is called; |
| * otherwise, this method does nothing and returns. |
| * <p> |
| * Subclasses of <code>Thread</code> should override this method. |
| * |
| * @see #start() |
| * @see #stop() |
| * @see #Thread(ThreadGroup, Runnable, String) |
| */ |
| @Override |
| public void run() { |
| if (target != null) { |
| target.run(); |
| } |
| } |
| |
| /** |
| * This method is called by the system to give a Thread |
| * a chance to clean up before it actually exits. |
| */ |
| private void exit() { |
| if (group != null) { |
| group.threadTerminated(this); |
| group = null; |
| } |
| /* Aggressively null out all reference fields: see bug 4006245 */ |
| target = null; |
| /* Speed the release of some of these resources */ |
| threadLocals = null; |
| inheritableThreadLocals = null; |
| inheritedAccessControlContext = null; |
| blocker = null; |
| uncaughtExceptionHandler = null; |
| } |
| |
| /** |
| * Forces the thread to stop executing. |
| * <p> |
| * If there is a security manager installed, its <code>checkAccess</code> |
| * method is called with <code>this</code> |
| * as its argument. This may result in a |
| * <code>SecurityException</code> being raised (in the current thread). |
| * <p> |
| * If this thread is different from the current thread (that is, the current |
| * thread is trying to stop a thread other than itself), the |
| * security manager's <code>checkPermission</code> method (with a |
| * <code>RuntimePermission("stopThread")</code> argument) is called in |
| * addition. |
| * Again, this may result in throwing a |
| * <code>SecurityException</code> (in the current thread). |
| * <p> |
| * The thread represented by this thread is forced to stop whatever |
| * it is doing abnormally and to throw a newly created |
| * <code>ThreadDeath</code> object as an exception. |
| * <p> |
| * It is permitted to stop a thread that has not yet been started. |
| * If the thread is eventually started, it immediately terminates. |
| * <p> |
| * An application should not normally try to catch |
| * <code>ThreadDeath</code> unless it must do some extraordinary |
| * cleanup operation (note that the throwing of |
| * <code>ThreadDeath</code> causes <code>finally</code> clauses of |
| * <code>try</code> statements to be executed before the thread |
| * officially dies). If a <code>catch</code> clause catches a |
| * <code>ThreadDeath</code> object, it is important to rethrow the |
| * object so that the thread actually dies. |
| * <p> |
| * The top-level error handler that reacts to otherwise uncaught |
| * exceptions does not print out a message or otherwise notify the |
| * application if the uncaught exception is an instance of |
| * <code>ThreadDeath</code>. |
| * |
| * @exception SecurityException if the current thread cannot |
| * modify this thread. |
| * @see #interrupt() |
| * @see #checkAccess() |
| * @see #run() |
| * @see #start() |
| * @see ThreadDeath |
| * @see ThreadGroup#uncaughtException(Thread,Throwable) |
| * @see SecurityManager#checkAccess(Thread) |
| * @see SecurityManager#checkPermission |
| * @deprecated This method is inherently unsafe. Stopping a thread with |
| * Thread.stop causes it to unlock all of the monitors that it |
| * has locked (as a natural consequence of the unchecked |
| * <code>ThreadDeath</code> exception propagating up the stack). If |
| * any of the objects previously protected by these monitors were in |
| * an inconsistent state, the damaged objects become visible to |
| * other threads, potentially resulting in arbitrary behavior. Many |
| * uses of <code>stop</code> should be replaced by code that simply |
| * modifies some variable to indicate that the target thread should |
| * stop running. The target thread should check this variable |
| * regularly, and return from its run method in an orderly fashion |
| * if the variable indicates that it is to stop running. If the |
| * target thread waits for long periods (on a condition variable, |
| * for example), the <code>interrupt</code> method should be used to |
| * interrupt the wait. |
| * For more information, see |
| * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why |
| * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>. |
| */ |
| @Deprecated |
| public final void stop() { |
| stop(new ThreadDeath()); |
| } |
| |
| /** |
| * Throws {@code UnsupportedOperationException}. |
| * |
| * @param obj ignored |
| * |
| * @deprecated This method was originally designed to force a thread to stop |
| * and throw a given {@code Throwable} as an exception. It was |
| * inherently unsafe (see {@link #stop()} for details), and furthermore |
| * could be used to generate exceptions that the target thread was |
| * not prepared to handle. |
| * For more information, see |
| * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why |
| * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>. |
| */ |
| @Deprecated |
| public final void stop(Throwable obj) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * Interrupts this thread. |
| * |
| * <p> Unless the current thread is interrupting itself, which is |
| * always permitted, the {@link #checkAccess() checkAccess} method |
| * of this thread is invoked, which may cause a {@link |
| * SecurityException} to be thrown. |
| * |
| * <p> If this thread is blocked in an invocation of the {@link |
| * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link |
| * Object#wait(long, int) wait(long, int)} methods of the {@link Object} |
| * class, or of the {@link #join()}, {@link #join(long)}, {@link |
| * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)}, |
| * methods of this class, then its interrupt status will be cleared and it |
| * will receive an {@link InterruptedException}. |
| * |
| * <p> If this thread is blocked in an I/O operation upon an {@link |
| * java.nio.channels.InterruptibleChannel InterruptibleChannel} |
| * then the channel will be closed, the thread's interrupt |
| * status will be set, and the thread will receive a {@link |
| * java.nio.channels.ClosedByInterruptException}. |
| * |
| * <p> If this thread is blocked in a {@link java.nio.channels.Selector} |
| * then the thread's interrupt status will be set and it will return |
| * immediately from the selection operation, possibly with a non-zero |
| * value, just as if the selector's {@link |
| * java.nio.channels.Selector#wakeup wakeup} method were invoked. |
| * |
| * <p> If none of the previous conditions hold then this thread's interrupt |
| * status will be set. </p> |
| * |
| * <p> Interrupting a thread that is not alive need not have any effect. |
| * |
| * @throws SecurityException |
| * if the current thread cannot modify this thread |
| * |
| * @revised 6.0 |
| * @spec JSR-51 |
| */ |
| public void interrupt() { |
| if (this != Thread.currentThread()) |
| checkAccess(); |
| |
| synchronized (blockerLock) { |
| Interruptible b = blocker; |
| if (b != null) { |
| nativeInterrupt(); |
| b.interrupt(this); |
| return; |
| } |
| } |
| nativeInterrupt(); |
| } |
| |
| /** |
| * Tests whether the current thread has been interrupted. The |
| * <i>interrupted status</i> of the thread is cleared by this method. In |
| * other words, if this method were to be called twice in succession, the |
| * second call would return false (unless the current thread were |
| * interrupted again, after the first call had cleared its interrupted |
| * status and before the second call had examined it). |
| * |
| * <p>A thread interruption ignored because a thread was not alive |
| * at the time of the interrupt will be reflected by this method |
| * returning false. |
| * |
| * @return <code>true</code> if the current thread has been interrupted; |
| * <code>false</code> otherwise. |
| * @see #isInterrupted() |
| * @revised 6.0 |
| */ |
| @FastNative |
| public static native boolean interrupted(); |
| |
| /** |
| * Tests whether this thread has been interrupted. The <i>interrupted |
| * status</i> of the thread is unaffected by this method. |
| * |
| * <p>A thread interruption ignored because a thread was not alive |
| * at the time of the interrupt will be reflected by this method |
| * returning false. |
| * |
| * @return <code>true</code> if this thread has been interrupted; |
| * <code>false</code> otherwise. |
| * @see #interrupted() |
| * @revised 6.0 |
| */ |
| @FastNative |
| public native boolean isInterrupted(); |
| |
| /** |
| * Throws {@link UnsupportedOperationException}. |
| * |
| * @deprecated This method was originally designed to destroy this |
| * thread without any cleanup. Any monitors it held would have |
| * remained locked. However, the method was never implemented. |
| * If if were to be implemented, it would be deadlock-prone in |
| * much the manner of {@link #suspend}. If the target thread held |
| * a lock protecting a critical system resource when it was |
| * destroyed, no thread could ever access this resource again. |
| * If another thread ever attempted to lock this resource, deadlock |
| * would result. Such deadlocks typically manifest themselves as |
| * "frozen" processes. For more information, see |
| * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/concurrency/threadPrimitiveDeprecation.html"> |
| * Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>. |
| * @throws UnsupportedOperationException always |
| */ |
| // Android-changed: Throw UnsupportedOperationException instead of |
| // NoSuchMethodError. |
| @Deprecated |
| public void destroy() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * Tests if this thread is alive. A thread is alive if it has |
| * been started and has not yet died. |
| * |
| * @return <code>true</code> if this thread is alive; |
| * <code>false</code> otherwise. |
| */ |
| public final boolean isAlive() { |
| return nativePeer != 0; |
| } |
| |
| /** |
| * Suspends this thread. |
| * <p> |
| * First, the <code>checkAccess</code> method of this thread is called |
| * with no arguments. This may result in throwing a |
| * <code>SecurityException </code>(in the current thread). |
| * <p> |
| * If the thread is alive, it is suspended and makes no further |
| * progress unless and until it is resumed. |
| * |
| * @exception SecurityException if the current thread cannot modify |
| * this thread. |
| * @see #checkAccess |
| * @deprecated This method has been deprecated, as it is |
| * inherently deadlock-prone. If the target thread holds a lock on the |
| * monitor protecting a critical system resource when it is suspended, no |
| * thread can access this resource until the target thread is resumed. If |
| * the thread that would resume the target thread attempts to lock this |
| * monitor prior to calling <code>resume</code>, deadlock results. Such |
| * deadlocks typically manifest themselves as "frozen" processes. |
| * For more information, see |
| * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why |
| * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>. |
| */ |
| @Deprecated |
| public final void suspend() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * Resumes a suspended thread. |
| * <p> |
| * First, the <code>checkAccess</code> method of this thread is called |
| * with no arguments. This may result in throwing a |
| * <code>SecurityException</code> (in the current thread). |
| * <p> |
| * If the thread is alive but suspended, it is resumed and is |
| * permitted to make progress in its execution. |
| * |
| * @exception SecurityException if the current thread cannot modify this |
| * thread. |
| * @see #checkAccess |
| * @see #suspend() |
| * @deprecated This method exists solely for use with {@link #suspend}, |
| * which has been deprecated because it is deadlock-prone. |
| * For more information, see |
| * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why |
| * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>. |
| */ |
| @Deprecated |
| public final void resume() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * Changes the priority of this thread. |
| * <p> |
| * First the <code>checkAccess</code> method of this thread is called |
| * with no arguments. This may result in throwing a |
| * <code>SecurityException</code>. |
| * <p> |
| * Otherwise, the priority of this thread is set to the smaller of |
| * the specified <code>newPriority</code> and the maximum permitted |
| * priority of the thread's thread group. |
| * |
| * @param newPriority priority to set this thread to |
| * @exception IllegalArgumentException If the priority is not in the |
| * range <code>MIN_PRIORITY</code> to |
| * <code>MAX_PRIORITY</code>. |
| * @exception SecurityException if the current thread cannot modify |
| * this thread. |
| * @see #getPriority |
| * @see #checkAccess() |
| * @see #getThreadGroup() |
| * @see #MAX_PRIORITY |
| * @see #MIN_PRIORITY |
| * @see ThreadGroup#getMaxPriority() |
| */ |
| public final void setPriority(int newPriority) { |
| ThreadGroup g; |
| checkAccess(); |
| if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) { |
| // Android-changed: Improve exception message when the new priority |
| // is out of bounds. |
| throw new IllegalArgumentException("Priority out of range: " + newPriority); |
| } |
| if((g = getThreadGroup()) != null) { |
| if (newPriority > g.getMaxPriority()) { |
| newPriority = g.getMaxPriority(); |
| } |
| synchronized(this) { |
| this.priority = newPriority; |
| if (isAlive()) { |
| nativeSetPriority(newPriority); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Returns this thread's priority. |
| * |
| * @return this thread's priority. |
| * @see #setPriority |
| */ |
| public final int getPriority() { |
| return priority; |
| } |
| |
| /** |
| * Changes the name of this thread to be equal to the argument |
| * <code>name</code>. |
| * <p> |
| * First the <code>checkAccess</code> method of this thread is called |
| * with no arguments. This may result in throwing a |
| * <code>SecurityException</code>. |
| * |
| * @param name the new name for this thread. |
| * @exception SecurityException if the current thread cannot modify this |
| * thread. |
| * @see #getName |
| * @see #checkAccess() |
| */ |
| public final void setName(String name) { |
| checkAccess(); |
| if (name == null) { |
| throw new NullPointerException("name == null"); |
| } |
| |
| synchronized (this) { |
| this.name = name; |
| if (isAlive()) { |
| nativeSetName(name); |
| } |
| } |
| } |
| |
| /** |
| * Returns this thread's name. |
| * |
| * @return this thread's name. |
| * @see #setName(String) |
| */ |
| public final String getName() { |
| return name; |
| } |
| |
| /** |
| * Returns the thread group to which this thread belongs. |
| * This method returns null if this thread has died |
| * (been stopped). |
| * |
| * @return this thread's thread group. |
| */ |
| public final ThreadGroup getThreadGroup() { |
| // Android-changed: Return null if the thread is terminated. |
| if (getState() == Thread.State.TERMINATED) { |
| return null; |
| } |
| return group; |
| } |
| |
| /** |
| * Returns an estimate of the number of active threads in the current |
| * thread's {@linkplain java.lang.ThreadGroup thread group} and its |
| * subgroups. Recursively iterates over all subgroups in the current |
| * thread's thread group. |
| * |
| * <p> The value returned is only an estimate because the number of |
| * threads may change dynamically while this method traverses internal |
| * data structures, and might be affected by the presence of certain |
| * system threads. This method is intended primarily for debugging |
| * and monitoring purposes. |
| * |
| * @return an estimate of the number of active threads in the current |
| * thread's thread group and in any other thread group that |
| * has the current thread's thread group as an ancestor |
| */ |
| public static int activeCount() { |
| return currentThread().getThreadGroup().activeCount(); |
| } |
| |
| /** |
| * Copies into the specified array every active thread in the current |
| * thread's thread group and its subgroups. This method simply |
| * invokes the {@link java.lang.ThreadGroup#enumerate(Thread[])} |
| * method of the current thread's thread group. |
| * |
| * <p> An application might use the {@linkplain #activeCount activeCount} |
| * method to get an estimate of how big the array should be, however |
| * <i>if the array is too short to hold all the threads, the extra threads |
| * are silently ignored.</i> If it is critical to obtain every active |
| * thread in the current thread's thread group and its subgroups, the |
| * invoker should verify that the returned int value is strictly less |
| * than the length of {@code tarray}. |
| * |
| * <p> Due to the inherent race condition in this method, it is recommended |
| * that the method only be used for debugging and monitoring purposes. |
| * |
| * @param tarray |
| * an array into which to put the list of threads |
| * |
| * @return the number of threads put into the array |
| * |
| * @throws SecurityException |
| * if {@link java.lang.ThreadGroup#checkAccess} determines that |
| * the current thread cannot access its thread group |
| */ |
| public static int enumerate(Thread tarray[]) { |
| return currentThread().getThreadGroup().enumerate(tarray); |
| } |
| |
| /** |
| * Counts the number of stack frames in this thread. The thread must |
| * be suspended. |
| * |
| * @return the number of stack frames in this thread. |
| * @exception IllegalThreadStateException if this thread is not |
| * suspended. |
| * @deprecated The definition of this call depends on {@link #suspend}, |
| * which is deprecated. Further, the results of this call |
| * were never well-defined. |
| */ |
| @Deprecated |
| public int countStackFrames() { |
| return getStackTrace().length; |
| } |
| |
| /** |
| * Waits at most {@code millis} milliseconds for this thread to |
| * die. A timeout of {@code 0} means to wait forever. |
| * |
| * <p> This implementation uses a loop of {@code this.wait} calls |
| * conditioned on {@code this.isAlive}. As a thread terminates the |
| * {@code this.notifyAll} method is invoked. It is recommended that |
| * applications not use {@code wait}, {@code notify}, or |
| * {@code notifyAll} on {@code Thread} instances. |
| * |
| * @param millis |
| * the time to wait in milliseconds |
| * |
| * @throws IllegalArgumentException |
| * if the value of {@code millis} is negative |
| * |
| * @throws InterruptedException |
| * if any thread has interrupted the current thread. The |
| * <i>interrupted status</i> of the current thread is |
| * cleared when this exception is thrown. |
| */ |
| public final void join(long millis) throws InterruptedException { |
| synchronized(lock) { |
| long base = System.currentTimeMillis(); |
| long now = 0; |
| |
| if (millis < 0) { |
| throw new IllegalArgumentException("timeout value is negative"); |
| } |
| |
| if (millis == 0) { |
| while (isAlive()) { |
| lock.wait(0); |
| } |
| } else { |
| while (isAlive()) { |
| long delay = millis - now; |
| if (delay <= 0) { |
| break; |
| } |
| lock.wait(delay); |
| now = System.currentTimeMillis() - base; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Waits at most {@code millis} milliseconds plus |
| * {@code nanos} nanoseconds for this thread to die. |
| * |
| * <p> This implementation uses a loop of {@code this.wait} calls |
| * conditioned on {@code this.isAlive}. As a thread terminates the |
| * {@code this.notifyAll} method is invoked. It is recommended that |
| * applications not use {@code wait}, {@code notify}, or |
| * {@code notifyAll} on {@code Thread} instances. |
| * |
| * @param millis |
| * the time to wait in milliseconds |
| * |
| * @param nanos |
| * {@code 0-999999} additional nanoseconds to wait |
| * |
| * @throws IllegalArgumentException |
| * if the value of {@code millis} is negative, or the value |
| * of {@code nanos} is not in the range {@code 0-999999} |
| * |
| * @throws InterruptedException |
| * if any thread has interrupted the current thread. The |
| * <i>interrupted status</i> of the current thread is |
| * cleared when this exception is thrown. |
| */ |
| public final void join(long millis, int nanos) |
| throws InterruptedException { |
| synchronized(lock) { |
| if (millis < 0) { |
| throw new IllegalArgumentException("timeout value is negative"); |
| } |
| |
| if (nanos < 0 || nanos > 999999) { |
| throw new IllegalArgumentException( |
| "nanosecond timeout value out of range"); |
| } |
| |
| if (nanos >= 500000 || (nanos != 0 && millis == 0)) { |
| millis++; |
| } |
| |
| join(millis); |
| } |
| } |
| |
| /** |
| * Waits for this thread to die. |
| * |
| * <p> An invocation of this method behaves in exactly the same |
| * way as the invocation |
| * |
| * <blockquote> |
| * {@linkplain #join(long) join}{@code (0)} |
| * </blockquote> |
| * |
| * @throws InterruptedException |
| * if any thread has interrupted the current thread. The |
| * <i>interrupted status</i> of the current thread is |
| * cleared when this exception is thrown. |
| */ |
| public final void join() throws InterruptedException { |
| join(0); |
| } |
| |
| /** |
| * Prints a stack trace of the current thread to the standard error stream. |
| * This method is used only for debugging. |
| * |
| * @see Throwable#printStackTrace() |
| */ |
| public static void dumpStack() { |
| new Exception("Stack trace").printStackTrace(); |
| } |
| |
| /** |
| * Marks this thread as either a {@linkplain #isDaemon daemon} thread |
| * or a user thread. The Java Virtual Machine exits when the only |
| * threads running are all daemon threads. |
| * |
| * <p> This method must be invoked before the thread is started. |
| * |
| * @param on |
| * if {@code true}, marks this thread as a daemon thread |
| * |
| * @throws IllegalThreadStateException |
| * if this thread is {@linkplain #isAlive alive} |
| * |
| * @throws SecurityException |
| * if {@link #checkAccess} determines that the current |
| * thread cannot modify this thread |
| */ |
| public final void setDaemon(boolean on) { |
| checkAccess(); |
| if (isAlive()) { |
| throw new IllegalThreadStateException(); |
| } |
| daemon = on; |
| } |
| |
| /** |
| * Tests if this thread is a daemon thread. |
| * |
| * @return <code>true</code> if this thread is a daemon thread; |
| * <code>false</code> otherwise. |
| * @see #setDaemon(boolean) |
| */ |
| public final boolean isDaemon() { |
| return daemon; |
| } |
| |
| /** |
| * Determines if the currently running thread has permission to |
| * modify this thread. |
| * <p> |
| * If there is a security manager, its <code>checkAccess</code> method |
| * is called with this thread as its argument. This may result in |
| * throwing a <code>SecurityException</code>. |
| * |
| * @exception SecurityException if the current thread is not allowed to |
| * access this thread. |
| * @see SecurityManager#checkAccess(Thread) |
| */ |
| public final void checkAccess() { |
| } |
| |
| /** |
| * Returns a string representation of this thread, including the |
| * thread's name, priority, and thread group. |
| * |
| * @return a string representation of this thread. |
| */ |
| public String toString() { |
| ThreadGroup group = getThreadGroup(); |
| if (group != null) { |
| return "Thread[" + getName() + "," + getPriority() + "," + |
| group.getName() + "]"; |
| } else { |
| return "Thread[" + getName() + "," + getPriority() + "," + |
| "" + "]"; |
| } |
| } |
| |
| /** |
| * Returns the context ClassLoader for this Thread. The context |
| * ClassLoader is provided by the creator of the thread for use |
| * by code running in this thread when loading classes and resources. |
| * If not {@linkplain #setContextClassLoader set}, the default is the |
| * ClassLoader context of the parent Thread. The context ClassLoader of the |
| * primordial thread is typically set to the class loader used to load the |
| * application. |
| * |
| * <p>If a security manager is present, and the invoker's class loader is not |
| * {@code null} and is not the same as or an ancestor of the context class |
| * loader, then this method invokes the security manager's {@link |
| * SecurityManager#checkPermission(java.security.Permission) checkPermission} |
| * method with a {@link RuntimePermission RuntimePermission}{@code |
| * ("getClassLoader")} permission to verify that retrieval of the context |
| * class loader is permitted. |
| * |
| * @return the context ClassLoader for this Thread, or {@code null} |
| * indicating the system class loader (or, failing that, the |
| * bootstrap class loader) |
| * |
| * @throws SecurityException |
| * if the current thread cannot get the context ClassLoader |
| * |
| * @since 1.2 |
| */ |
| @CallerSensitive |
| public ClassLoader getContextClassLoader() { |
| return contextClassLoader; |
| } |
| |
| /** |
| * Sets the context ClassLoader for this Thread. The context |
| * ClassLoader can be set when a thread is created, and allows |
| * the creator of the thread to provide the appropriate class loader, |
| * through {@code getContextClassLoader}, to code running in the thread |
| * when loading classes and resources. |
| * |
| * <p>If a security manager is present, its {@link |
| * SecurityManager#checkPermission(java.security.Permission) checkPermission} |
| * method is invoked with a {@link RuntimePermission RuntimePermission}{@code |
| * ("setContextClassLoader")} permission to see if setting the context |
| * ClassLoader is permitted. |
| * |
| * @param cl |
| * the context ClassLoader for this Thread, or null indicating the |
| * system class loader (or, failing that, the bootstrap class loader) |
| * |
| * @throws SecurityException |
| * if the current thread cannot set the context ClassLoader |
| * |
| * @since 1.2 |
| */ |
| public void setContextClassLoader(ClassLoader cl) { |
| contextClassLoader = cl; |
| } |
| |
| /** |
| * Returns <tt>true</tt> if and only if the current thread holds the |
| * monitor lock on the specified object. |
| * |
| * <p>This method is designed to allow a program to assert that |
| * the current thread already holds a specified lock: |
| * <pre> |
| * assert Thread.holdsLock(obj); |
| * </pre> |
| * |
| * @param obj the object on which to test lock ownership |
| * @throws NullPointerException if obj is <tt>null</tt> |
| * @return <tt>true</tt> if the current thread holds the monitor lock on |
| * the specified object. |
| * @since 1.4 |
| */ |
| public static boolean holdsLock(Object obj) { |
| return currentThread().nativeHoldsLock(obj); |
| } |
| |
| private native boolean nativeHoldsLock(Object object); |
| |
| private static final StackTraceElement[] EMPTY_STACK_TRACE |
| = new StackTraceElement[0]; |
| |
| /** |
| * Returns an array of stack trace elements representing the stack dump |
| * of this thread. This method will return a zero-length array if |
| * this thread has not started, has started but has not yet been |
| * scheduled to run by the system, or has terminated. |
| * If the returned array is of non-zero length then the first element of |
| * the array represents the top of the stack, which is the most recent |
| * method invocation in the sequence. The last element of the array |
| * represents the bottom of the stack, which is the least recent method |
| * invocation in the sequence. |
| * |
| * <p>If there is a security manager, and this thread is not |
| * the current thread, then the security manager's |
| * <tt>checkPermission</tt> method is called with a |
| * <tt>RuntimePermission("getStackTrace")</tt> permission |
| * to see if it's ok to get the stack trace. |
| * |
| * <p>Some virtual machines may, under some circumstances, omit one |
| * or more stack frames from the stack trace. In the extreme case, |
| * a virtual machine that has no stack trace information concerning |
| * this thread is permitted to return a zero-length array from this |
| * method. |
| * |
| * @return an array of <tt>StackTraceElement</tt>, |
| * each represents one stack frame. |
| * |
| * @throws SecurityException |
| * if a security manager exists and its |
| * <tt>checkPermission</tt> method doesn't allow |
| * getting the stack trace of thread. |
| * @see SecurityManager#checkPermission |
| * @see RuntimePermission |
| * @see Throwable#getStackTrace |
| * |
| * @since 1.5 |
| */ |
| public StackTraceElement[] getStackTrace() { |
| StackTraceElement ste[] = VMStack.getThreadStackTrace(this); |
| return ste != null ? ste : EmptyArray.STACK_TRACE_ELEMENT; |
| } |
| |
| /** |
| * Returns a map of stack traces for all live threads. |
| * The map keys are threads and each map value is an array of |
| * <tt>StackTraceElement</tt> that represents the stack dump |
| * of the corresponding <tt>Thread</tt>. |
| * The returned stack traces are in the format specified for |
| * the {@link #getStackTrace getStackTrace} method. |
| * |
| * <p>The threads may be executing while this method is called. |
| * The stack trace of each thread only represents a snapshot and |
| * each stack trace may be obtained at different time. A zero-length |
| * array will be returned in the map value if the virtual machine has |
| * no stack trace information about a thread. |
| * |
| * <p>If there is a security manager, then the security manager's |
| * <tt>checkPermission</tt> method is called with a |
| * <tt>RuntimePermission("getStackTrace")</tt> permission as well as |
| * <tt>RuntimePermission("modifyThreadGroup")</tt> permission |
| * to see if it is ok to get the stack trace of all threads. |
| * |
| * @return a <tt>Map</tt> from <tt>Thread</tt> to an array of |
| * <tt>StackTraceElement</tt> that represents the stack trace of |
| * the corresponding thread. |
| * |
| * @throws SecurityException |
| * if a security manager exists and its |
| * <tt>checkPermission</tt> method doesn't allow |
| * getting the stack trace of thread. |
| * @see #getStackTrace |
| * @see SecurityManager#checkPermission |
| * @see RuntimePermission |
| * @see Throwable#getStackTrace |
| * |
| * @since 1.5 |
| */ |
| 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.systemThreadGroup.activeCount(); |
| Thread[] threads = new Thread[count + count / 2]; |
| |
| // Enumerate the threads and collect the stacktraces. |
| count = ThreadGroup.systemThreadGroup.enumerate(threads); |
| for (int i = 0; i < count; i++) { |
| map.put(threads[i], threads[i].getStackTrace()); |
| } |
| |
| return map; |
| } |
| |
| |
| private static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION = |
| new RuntimePermission("enableContextClassLoaderOverride"); |
| |
| /** cache of subclass security audit results */ |
| /* Replace with ConcurrentReferenceHashMap when/if it appears in a future |
| * release */ |
| private static class Caches { |
| /** cache of subclass security audit results */ |
| static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits = |
| new ConcurrentHashMap<>(); |
| |
| /** queue for WeakReferences to audited subclasses */ |
| static final ReferenceQueue<Class<?>> subclassAuditsQueue = |
| new ReferenceQueue<>(); |
| } |
| |
| /** |
| * Verifies that this (possibly subclass) instance can be constructed |
| * without violating security constraints: the subclass must not override |
| * security-sensitive non-final methods, or else the |
| * "enableContextClassLoaderOverride" RuntimePermission is checked. |
| */ |
| private static boolean isCCLOverridden(Class<?> cl) { |
| if (cl == Thread.class) |
| return false; |
| |
| processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits); |
| WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue); |
| Boolean result = Caches.subclassAudits.get(key); |
| if (result == null) { |
| result = Boolean.valueOf(auditSubclass(cl)); |
| Caches.subclassAudits.putIfAbsent(key, result); |
| } |
| |
| return result.booleanValue(); |
| } |
| |
| /** |
| * Performs reflective checks on given subclass to verify that it doesn't |
| * override security-sensitive non-final methods. Returns true if the |
| * subclass overrides any of the methods, false otherwise. |
| */ |
| private static boolean auditSubclass(final Class<?> subcl) { |
| Boolean result = AccessController.doPrivileged( |
| new PrivilegedAction<Boolean>() { |
| public Boolean run() { |
| for (Class<?> cl = subcl; |
| cl != Thread.class; |
| cl = cl.getSuperclass()) |
| { |
| try { |
| cl.getDeclaredMethod("getContextClassLoader", new Class<?>[0]); |
| return Boolean.TRUE; |
| } catch (NoSuchMethodException ex) { |
| } |
| try { |
| Class<?>[] params = {ClassLoader.class}; |
| cl.getDeclaredMethod("setContextClassLoader", params); |
| return Boolean.TRUE; |
| } catch (NoSuchMethodException ex) { |
| } |
| } |
| return Boolean.FALSE; |
| } |
| } |
| ); |
| return result.booleanValue(); |
| } |
| |
| /** |
| * Returns the identifier of this Thread. The thread ID is a positive |
| * <tt>long</tt> number generated when this thread was created. |
| * The thread ID is unique and remains unchanged during its lifetime. |
| * When a thread is terminated, this thread ID may be reused. |
| * |
| * @return this thread's ID. |
| * @since 1.5 |
| */ |
| public long getId() { |
| return tid; |
| } |
| |
| /** |
| * A thread state. A thread can be in one of the following states: |
| * <ul> |
| * <li>{@link #NEW}<br> |
| * A thread that has not yet started is in this state. |
| * </li> |
| * <li>{@link #RUNNABLE}<br> |
| * A thread executing in the Java virtual machine is in this state. |
| * </li> |
| * <li>{@link #BLOCKED}<br> |
| * A thread that is blocked waiting for a monitor lock |
| * is in this state. |
| * </li> |
| * <li>{@link #WAITING}<br> |
| * A thread that is waiting indefinitely for another thread to |
| * perform a particular action is in this state. |
| * </li> |
| * <li>{@link #TIMED_WAITING}<br> |
| * A thread that is waiting for another thread to perform an action |
| * for up to a specified waiting time is in this state. |
| * </li> |
| * <li>{@link #TERMINATED}<br> |
| * A thread that has exited is in this state. |
| * </li> |
| * </ul> |
| * |
| * <p> |
| * A thread can be in only one state at a given point in time. |
| * These states are virtual machine states which do not reflect |
| * any operating system thread states. |
| * |
| * @since 1.5 |
| * @see #getState |
| */ |
| public enum State { |
| /** |
| * Thread state for a thread which has not yet started. |
| */ |
| NEW, |
| |
| /** |
| * Thread state for a runnable thread. A thread in the runnable |
| * state is executing in the Java virtual machine but it may |
| * be waiting for other resources from the operating system |
| * such as processor. |
| */ |
| RUNNABLE, |
| |
| /** |
| * Thread state for a thread blocked waiting for a monitor lock. |
| * A thread in the blocked state is waiting for a monitor lock |
| * to enter a synchronized block/method or |
| * reenter a synchronized block/method after calling |
| * {@link Object#wait() Object.wait}. |
| */ |
| BLOCKED, |
| |
| /** |
| * Thread state for a waiting thread. |
| * A thread is in the waiting state due to calling one of the |
| * following methods: |
| * <ul> |
| * <li>{@link Object#wait() Object.wait} with no timeout</li> |
| * <li>{@link #join() Thread.join} with no timeout</li> |
| * <li>{@link LockSupport#park() LockSupport.park}</li> |
| * </ul> |
| * |
| * <p>A thread in the waiting state is waiting for another thread to |
| * perform a particular action. |
| * |
| * For example, a thread that has called <tt>Object.wait()</tt> |
| * on an object is waiting for another thread to call |
| * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on |
| * that object. A thread that has called <tt>Thread.join()</tt> |
| * is waiting for a specified thread to terminate. |
| */ |
| WAITING, |
| |
| /** |
| * Thread state for a waiting thread with a specified waiting time. |
| * A thread is in the timed waiting state due to calling one of |
| * the following methods with a specified positive waiting time: |
| * <ul> |
| * <li>{@link #sleep Thread.sleep}</li> |
| * <li>{@link Object#wait(long) Object.wait} with timeout</li> |
| * <li>{@link #join(long) Thread.join} with timeout</li> |
| * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li> |
| * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li> |
| * </ul> |
| */ |
| TIMED_WAITING, |
| |
| /** |
| * Thread state for a terminated thread. |
| * The thread has completed execution. |
| */ |
| TERMINATED; |
| } |
| |
| /** |
| * Returns the state of this thread. |
| * This method is designed for use in monitoring of the system state, |
| * not for synchronization control. |
| * |
| * @return this thread's state. |
| * @since 1.5 |
| */ |
| public State getState() { |
| // get current thread state |
| return State.values()[nativeGetStatus(started)]; |
| } |
| |
| // Added in JSR-166 |
| |
| /** |
| * Interface for handlers invoked when a <tt>Thread</tt> abruptly |
| * terminates due to an uncaught exception. |
| * <p>When a thread is about to terminate due to an uncaught exception |
| * the Java Virtual Machine will query the thread for its |
| * <tt>UncaughtExceptionHandler</tt> using |
| * {@link #getUncaughtExceptionHandler} and will invoke the handler's |
| * <tt>uncaughtException</tt> method, passing the thread and the |
| * exception as arguments. |
| * If a thread has not had its <tt>UncaughtExceptionHandler</tt> |
| * explicitly set, then its <tt>ThreadGroup</tt> object acts as its |
| * <tt>UncaughtExceptionHandler</tt>. If the <tt>ThreadGroup</tt> object |
| * has no |
| * special requirements for dealing with the exception, it can forward |
| * the invocation to the {@linkplain #getDefaultUncaughtExceptionHandler |
| * default uncaught exception handler}. |
| * |
| * @see #setDefaultUncaughtExceptionHandler |
| * @see #setUncaughtExceptionHandler |
| * @see ThreadGroup#uncaughtException |
| * @since 1.5 |
| */ |
| @FunctionalInterface |
| public interface UncaughtExceptionHandler { |
| /** |
| * Method invoked when the given thread terminates due to the |
| * given uncaught exception. |
| * <p>Any exception thrown by this method will be ignored by the |
| * Java Virtual Machine. |
| * @param t the thread |
| * @param e the exception |
| */ |
| void uncaughtException(Thread t, Throwable e); |
| } |
| |
| // null unless explicitly set |
| private volatile UncaughtExceptionHandler uncaughtExceptionHandler; |
| |
| // null unless explicitly set |
| private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler; |
| |
| /** |
| * Set the default handler invoked when a thread abruptly terminates |
| * due to an uncaught exception, and no other handler has been defined |
| * for that thread. |
| * |
| * <p>Uncaught exception handling is controlled first by the thread, then |
| * by the thread's {@link ThreadGroup} object and finally by the default |
| * uncaught exception handler. If the thread does not have an explicit |
| * uncaught exception handler set, and the thread's thread group |
| * (including parent thread groups) does not specialize its |
| * <tt>uncaughtException</tt> method, then the default handler's |
| * <tt>uncaughtException</tt> method will be invoked. |
| * <p>By setting the default uncaught exception handler, an application |
| * can change the way in which uncaught exceptions are handled (such as |
| * logging to a specific device, or file) for those threads that would |
| * already accept whatever "default" behavior the system |
| * provided. |
| * |
| * <p>Note that the default uncaught exception handler should not usually |
| * defer to the thread's <tt>ThreadGroup</tt> object, as that could cause |
| * infinite recursion. |
| * |
| * @param eh the object to use as the default uncaught exception handler. |
| * If <tt>null</tt> then there is no default handler. |
| * |
| * @throws SecurityException if a security manager is present and it |
| * denies <tt>{@link RuntimePermission} |
| * ("setDefaultUncaughtExceptionHandler")</tt> |
| * |
| * @see #setUncaughtExceptionHandler |
| * @see #getUncaughtExceptionHandler |
| * @see ThreadGroup#uncaughtException |
| * @since 1.5 |
| */ |
| public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) { |
| defaultUncaughtExceptionHandler = eh; |
| } |
| |
| /** |
| * Returns the default handler invoked when a thread abruptly terminates |
| * due to an uncaught exception. If the returned value is <tt>null</tt>, |
| * there is no default. |
| * @since 1.5 |
| * @see #setDefaultUncaughtExceptionHandler |
| * @return the default uncaught exception handler for all threads |
| */ |
| public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){ |
| return defaultUncaughtExceptionHandler; |
| } |
| |
| // Android-changed: Added concept of an uncaughtExceptionPreHandler for use by platform. |
| // null unless explicitly set |
| private static volatile UncaughtExceptionHandler uncaughtExceptionPreHandler; |
| |
| /** |
| * Sets an {@link UncaughtExceptionHandler} that will be called before any |
| * returned by {@link #getUncaughtExceptionHandler()}. To allow the standard |
| * handlers to run, this handler should never terminate this process. Any |
| * throwables thrown by the handler will be ignored by |
| * {@link #dispatchUncaughtException(Throwable)}. |
| * |
| * @hide only for use by the Android framework (RuntimeInit) b/29624607 |
| */ |
| public static void setUncaughtExceptionPreHandler(UncaughtExceptionHandler eh) { |
| uncaughtExceptionPreHandler = eh; |
| } |
| |
| /** @hide */ |
| public static UncaughtExceptionHandler getUncaughtExceptionPreHandler() { |
| return uncaughtExceptionPreHandler; |
| } |
| |
| /** |
| * Returns the handler invoked when this thread abruptly terminates |
| * due to an uncaught exception. If this thread has not had an |
| * uncaught exception handler explicitly set then this thread's |
| * <tt>ThreadGroup</tt> object is returned, unless this thread |
| * has terminated, in which case <tt>null</tt> is returned. |
| * @since 1.5 |
| * @return the uncaught exception handler for this thread |
| */ |
| public UncaughtExceptionHandler getUncaughtExceptionHandler() { |
| return uncaughtExceptionHandler != null ? |
| uncaughtExceptionHandler : group; |
| } |
| |
| /** |
| * Set the handler invoked when this thread abruptly terminates |
| * due to an uncaught exception. |
| * <p>A thread can take full control of how it responds to uncaught |
| * exceptions by having its uncaught exception handler explicitly set. |
| * If no such handler is set then the thread's <tt>ThreadGroup</tt> |
| * object acts as its handler. |
| * @param eh the object to use as this thread's uncaught exception |
| * handler. If <tt>null</tt> then this thread has no explicit handler. |
| * @throws SecurityException if the current thread is not allowed to |
| * modify this thread. |
| * @see #setDefaultUncaughtExceptionHandler |
| * @see ThreadGroup#uncaughtException |
| * @since 1.5 |
| */ |
| public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) { |
| checkAccess(); |
| uncaughtExceptionHandler = eh; |
| } |
| |
| /** |
| * Dispatch an uncaught exception to the handler. This method is |
| * intended to be called only by the runtime and by tests. |
| * |
| * @hide |
| */ |
| // @VisibleForTesting (would be package-private if not for tests) |
| public final void dispatchUncaughtException(Throwable e) { |
| Thread.UncaughtExceptionHandler initialUeh = |
| Thread.getUncaughtExceptionPreHandler(); |
| if (initialUeh != null) { |
| try { |
| initialUeh.uncaughtException(this, e); |
| } catch (RuntimeException | Error ignored) { |
| // Throwables thrown by the initial handler are ignored |
| } |
| } |
| getUncaughtExceptionHandler().uncaughtException(this, e); |
| } |
| |
| /** |
| * Removes from the specified map any keys that have been enqueued |
| * on the specified reference queue. |
| */ |
| static void processQueue(ReferenceQueue<Class<?>> queue, |
| ConcurrentMap<? extends |
| WeakReference<Class<?>>, ?> map) |
| { |
| Reference<? extends Class<?>> ref; |
| while((ref = queue.poll()) != null) { |
| map.remove(ref); |
| } |
| } |
| |
| /** |
| * Weak key for Class objects. |
| **/ |
| static class WeakClassKey extends WeakReference<Class<?>> { |
| /** |
| * saved value of the referent's identity hash code, to maintain |
| * a consistent hash code after the referent has been cleared |
| */ |
| private final int hash; |
| |
| /** |
| * Create a new WeakClassKey to the given object, registered |
| * with a queue. |
| */ |
| WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) { |
| super(cl, refQueue); |
| hash = System.identityHashCode(cl); |
| } |
| |
| /** |
| * Returns the identity hash code of the original referent. |
| */ |
| @Override |
| public int hashCode() { |
| return hash; |
| } |
| |
| /** |
| * Returns true if the given object is this identical |
| * WeakClassKey instance, or, if this object's referent has not |
| * been cleared, if the given object is another WeakClassKey |
| * instance with the identical non-null referent as this one. |
| */ |
| @Override |
| public boolean equals(Object obj) { |
| if (obj == this) |
| return true; |
| |
| if (obj instanceof WeakClassKey) { |
| Object referent = get(); |
| return (referent != null) && |
| (referent == ((WeakClassKey) obj).get()); |
| } else { |
| return false; |
| } |
| } |
| } |
| |
| |
| // The following three initially uninitialized fields are exclusively |
| // managed by class java.util.concurrent.ThreadLocalRandom. These |
| // fields are used to build the high-performance PRNGs in the |
| // concurrent code, and we can not risk accidental false sharing. |
| // Hence, the fields are isolated with @Contended. |
| |
| /** The current seed for a ThreadLocalRandom */ |
| // @sun.misc.Contended("tlr") |
| long threadLocalRandomSeed; |
| |
| /** Probe hash value; nonzero if threadLocalRandomSeed initialized */ |
| // @sun.misc.Contended("tlr") |
| int threadLocalRandomProbe; |
| |
| /** Secondary seed isolated from public ThreadLocalRandom sequence */ |
| // @sun.misc.Contended("tlr") |
| int threadLocalRandomSecondarySeed; |
| |
| /* Some private helper methods */ |
| private native void nativeSetName(String newName); |
| |
| private native void nativeSetPriority(int newPriority); |
| |
| private native int nativeGetStatus(boolean hasBeenStarted); |
| |
| @FastNative |
| private native void nativeInterrupt(); |
| |
| /** 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; |
| } |
| |
| private static final int NANOS_PER_MILLI = 1000000; |
| |
| /** the park state of the thread */ |
| private int parkState = ParkState.UNPARKED; |
| |
| /** |
| * 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 final void unpark$() { |
| 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). |
| * |
| * <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 < 0</code> |
| * |
| * @hide for Unsafe |
| */ |
| public final void parkFor$(long nanos) { |
| 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("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 final void parkUntil$(long time) { |
| 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. |
| */ |
| final long currentTime = System.currentTimeMillis(); |
| if (time <= currentTime) { |
| parkState = ParkState.UNPARKED; |
| } else { |
| long delayMillis = time - currentTime; |
| // Long.MAX_VALUE / NANOS_PER_MILLI (0x8637BD05SF6) is the largest |
| // long value that won't overflow to negative value when |
| // multiplyed by NANOS_PER_MILLI (10^6). |
| long maxValue = (Long.MAX_VALUE / NANOS_PER_MILLI); |
| if (delayMillis > maxValue) { |
| delayMillis = maxValue; |
| } |
| parkFor$(delayMillis * NANOS_PER_MILLI); |
| } |
| } |
| } |
| } |