点击此处去Gitee上Clone源码下来在IDE上看效果更佳
package java.lang;
import sun.nio.ch.Interruptible;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.security.util.SecurityConstants;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.LockSupport;
public class Thread implements Runnable {
/* 确保registerNatives是<clinit>要做的第一件事 */
private static native void registerNatives();
static {
registerNatives();
}
/*我认为重要的字段*/
/**
* 线程名
*/
private volatile String name;
/**
* 优先级
*/
private int priority;
/**
* 线程可以具有的最低优先级。
*/
public final static int MIN_PRIORITY = 1;
/**
* 分配给线程的默认优先级。
*/
public final static int NORM_PRIORITY = 5;
/**
* 线程可以具有的最大优先级。
*/
public final static int MAX_PRIORITY = 10;
/* 该线程是否是守护程序线程。 */
private boolean daemon = false;
/*传入的Runnable */
private Runnable target;
/* 该线程的ThreadGroup */
private ThreadGroup group;
/* 此线程的ThreadLocalMap,该Map由ThreadLocal类维护*/
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
此线程的可以继承的ThreadLocalMap,该Map由InheritableThreadLocal类维护
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
/*线程的6种状态*/
/**
* 在给定的时间点,线程只能处于一种状态。 这些状态是虚拟机状态,不反映任何操作系统线程状态。
* <pre>
* WAITING TIMED_WAITING
* ↑ ↑
* Object.wait() Thread.sleep(long)
* Thread.join() LockSupport.parkNanos(long)
* LockSupport.park() LockSupport.parkUntil(long)
* \ Object.wait(long)
* \ |
* NEW--start()-——-> RUNNABLE--运行完成或者被中断->TERMINATED
* |
* |
* 等待获得monitor lock
* |
* V
* BLOCKED
* </pre>
*
* @see #getState
*/
public enum State {
/**
* 一个new好的线程尚未start的状态
*/
NEW,
/**
* 可运行线程的线程状态。
* 处于可运行状态的线程正在Java虚拟机中执行,
* 但它可能正在等待来自操作系统(例如处理器)的其他资源。
*/
RUNNABLE,
/**
* 等待获取monitor lock的阻塞状态。
* 比如等待进入 synchronized 修饰的代码块或方法时。
*/
BLOCKED,
/**
* 等待状态
* 调用以下方法之一,线程会进入等待状态。
* <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>
* 处于等待状态的线程正在等待另一个线程执行特定操作。
* 例如,在某个对象上调用Object.wait()的线程正在等待另一个线程在该对象上调用Object.notify()或Object.notifyAll()。
* 调用Thread.join()的线程正在等待指定的线程终止。
*/
WAITING,
/**
* 定时等待状态
* 具有指定等待时间的等待线程的线程状态。调用以下方法之一进入:
* <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,
/**
* 线程的终止状态。线程已完成执行。
*/
TERMINATED;
}
/*构造函数*/
/**
* 无参
*/
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
/**
* 传入Runnable
*/
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
/**
* 不是public的,不用管
* Creates a new Thread that inherits the given AccessControlContext.
* This is not a public constructor.
*/
Thread(Runnable target, AccessControlContext acc) {
init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
}
/**
* ThreadGroup底层用了Thread[] threads来储存Thread
* 可以通过ThreadGroup来批量操作Thread
*/
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(String name) {
init(null, null, name, 0);
}
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
}
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
/**
* stackSize参数的效果(如果有的话)高度依赖于平台。
* 在某些平台上,为stackSize参数指定更高的值可能会允许线程在抛出stackoverflowerr之前获得更大的递归深度。
* 类似地,指定一个较低的值可以允许更多的线程同时存在,而不会抛出OutOfMemoryError(或其他内部错误)。
* stackSize参数值与最大递归深度和并发级别之间关系的详细信息取决于平台。
* 在某些平台上,stackSize参数的值可能没有任何影响。
* <p>
* 虚拟机可以自由地将stackSize参数作为建议处理。
* 如果平台的指定值不合理地低,虚拟机可以使用某些特定于平台的最小值;
* 如果指定的值不合理地高,虚拟机可以使用特定于平台的某些最大值。
* 同样,虚拟机可以自由地向上或向下取整指定的值(或者完全忽略它)。
* <p>
* 由于此构造函数的行为依赖于平台,因此在使用时应格外小心。
* 执行给定计算所需的线程堆栈大小可能因JRE实现而异。
* 考虑到这种变化,可能需要对堆栈大小参数进行仔细的调优,并且可能需要对运行应用程序的每个JRE实现重复调优。
*
* @param stackSize 新线程的所需堆栈大小,或者为0表示要忽略此参数。
*/
public Thread(ThreadGroup group, Runnable target, String name, long stackSize) {
init(group, target, name, stackSize);
}
/**
* 使用当前的AccessControlContext初始化线程。
*
* @see #init(ThreadGroup, Runnable, String, long, AccessControlContext, boolean)
*/
private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
init(g, target, name, stackSize, null, true);
}
/**
* 初始化线程。
*
* @param g the Thread group
* @param target 传入的Runnable
* @param name 新线程的名称
* @param stackSize 新线程的所需堆栈大小,或者为0表示要忽略此参数。
* @param acc 要继承的AccessControlContext;如果为null,则为AccessController.getContext()
* @param inheritThreadLocals if {@code true}, 从调用构造器的线程继承可继承{@link inheritableThreadLocals}的初始值
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;//设置name
Thread parent = currentThread();//设置parent为当前线程
SecurityManager security = System.getSecurityManager();
if (g == null) {//没有传入ThreadGroup
/* 问一下SecurityManager该如何是好 */
if (security != null) {
g = security.getThreadGroup();
}
/* SecurityManager不想处理就使用父类的ThreadGroup*/
if (g == null) {
g = parent.getThreadGroup();
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;//设置group
this.daemon = parent.isDaemon();//继承父类守护属性
this.priority = parent.getPriority();//继承父类优先级
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext = acc != null ? acc : AccessController.getContext();
this.target = target;//执行的Runnable
setPriority(priority);//设置优先级
if (inheritThreadLocals && parent.inheritableThreadLocals != null) {
//需要继承父线程的inheritThreadLocals并且父线程的inheritableThreadLocals有值
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
}
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
/*常用方法*/
/**
* 当前线程
*/
public static native Thread currentThread();
/**
* 给调度程序的提示是当前线程愿意放弃对处理器的当前使用。调度程序可以随意忽略此提示。
* <p>
* Yield是一种启发式尝试,旨在改善线程之间的相对进程,否则将过度利用CPU。
* 应将其使用与详细的性能分析和基准测试结合起来,以确保它实际上具有所需的效果。
* <p>
* 很少适合使用此方法。它可能对调试或测试有用,因为它可能有助于重现由于竞争条件而产生的错误。
* 当设计并发控制结构(例如,{@link java.util.concurrent.locks} 包).
*/
public static native void yield();
/**
* 当前线程进入TIMED_WAITING状态,不会释放锁。
*
* @param millis 睡眠时间(以毫秒为单位)
* @throws IllegalArgumentException 如果{@code millis}的值为负
* @throws InterruptedException 如果有任何线程中断了当前线程。抛出此异常时,将清除当前线程的中断状态,则将Interrupted设置未false。
*/
public static native void sleep(long millis) throws InterruptedException;
/**
* 当前线程进入TIMED_WAITING状态,不会释放锁。
*
* @param millis 睡眠时间(以毫秒为单位)
* @param nanos {@code 0-999999} 额外的纳秒睡眠
* @throws IllegalArgumentException 如果{@code millis}的值为负,
* 或者{@code nanos}的值不在{@code 0-999999}范围内
* @throws InterruptedException 如果有任何线程中断了当前线程。抛出此异常时,将清除当前线程的<i>interrupted status</i>。
*/
public static void sleep(long millis, int nanos)
throws InterruptedException {
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++;
}
sleep(millis);
}
/**
* 启动此线程,一个线程只能启动一次。
*
* @throws IllegalThreadStateException 如果线程已经启动。
*/
public synchronized void start() {
/**
不是NEW状态则抛出异常
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* 通知组该线程将要启动,以便可以将其添加到组的线程列表中,并且组的未启动计数可以减少。 */
group.add(this);
boolean started = false;
try {
start0();
//启动成功
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* 没做什么。如果start0抛出了Throwable,则它将被向上传递到调用堆栈*/
}
}
}
/*线程的中断*/
/**
* 将此线程设置为中断状态。
* 这只是一种通信方式并不会直接中断此线程,线程需要自己轮询中断状态来响应中断请求。
* 如果此线程在调用对象类的wait()、wait(long)或wait(long,int)方法或
* 该类的join()、join(long)、join(long,int)、sleep(long)或sleep(long,int)方法阻塞被中断时,
* 则其中断状态将被清除,并将收到InterruptedException。
*/
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}
/**
* 返回当前线程是处于中断状态,调用后会清空中断状态。既连续调用2次此方法第二次必返回false
*/
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
/**
* 返回当前线程是处于中断状态。
*/
public boolean isInterrupted() {
return isInterrupted(false);
}
/**
* 此线程插入当前运行的线程之前运行,带有超时时间。
*/
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
/**
* 此线程插入当前运行的线程之前运行,带有超时时间。
*/
public final synchronized void join(long millis, int nanos)
throws InterruptedException {
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);
}
/**
* 此线程插入当前运行的线程之前运行。
*/
public final void join() throws InterruptedException {
join(0);
}
/**
* 更改此线程的优先级。
*/
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if ((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
public final int getPriority() {
return priority;
}
public final synchronized void setName(String name) {
checkAccess();
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
if (threadStatus != 0) {
setNativeName(name);
}
}
public final String getName() {
return name;
}
/**
* 返回该线程所属的线程组。如果该线程死亡(已停止),则此方法返回null。
*/
public final ThreadGroup getThreadGroup() {
return group;
}
/**
* 返回当前线程的线程组及其子组中活动线程的数量的估计值。
* 递归地迭代当前线程的线程组中的所有子组。
* 返回的值只是一个估计值,因为此方法遍历内部数据结构时线程数可能会动态变化,
* 并且可能会受某些系统线程的存在的影响。此方法主要用于调试和监视目的。
*/
public static int activeCount() {
return currentThread().getThreadGroup().activeCount();
}
private Thread threadQ;
private long eetop;
/* 是否单步执行此线程。 */
private boolean single_step;
/* JVM state */
private boolean stillborn = false;
/* 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++;
}
/*
* 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
*/
void blockedOn(Interruptible b) {
synchronized (blockerLock) {
blocker = b;
}
}
/**
* 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();
}
private native void start0();
/**
* 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;
}
@Deprecated
public final void stop() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
checkAccess();
if (this != Thread.currentThread()) {
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
}
}
// A zero status value corresponds to "NEW", it can't change to
// not-NEW because we hold the lock.
if (threadStatus != 0) {
resume(); // Wake up thread if it was suspended; no-op otherwise
}
// The VM can handle all thread states
stop0(new ThreadDeath());
}
public final synchronized void stop(Throwable obj) {
throw new UnsupportedOperationException();
}
/**
* Tests if some Thread has been interrupted. The interrupted state
* is reset or not based on the value of ClearInterrupted that is
* passed.
*/
private native boolean isInterrupted(boolean ClearInterrupted);
/**
* 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 native boolean isAlive();
@Deprecated
public void destroy() {
throw new NoSuchMethodError();
}
@Deprecated
public final void suspend() {
checkAccess();
suspend0();
}
@Deprecated
public final void resume() {
checkAccess();
resume0();
}
/**
* 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.
* @throws 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 native int countStackFrames();
/**
* 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();
}
/**
* 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>.
*
* @throws SecurityException if the current thread is not allowed to
* access this thread.
* @see SecurityManager#checkAccess(Thread)
*/
public final void checkAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkAccess(this);
}
}
/**
* 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() {
if (contextClassLoader == null)
return null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader.checkClassLoaderPermission(contextClassLoader,
Reflection.getCallerClass());
}
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) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
}
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
* @return <tt>true</tt> if the current thread holds the monitor lock on
* the specified object.
* @throws NullPointerException if obj is <tt>null</tt>
* @since 1.4
*/
public static native boolean holdsLock(Object obj);
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() {
if (this != Thread.currentThread()) {
// check for getStackTrace permission
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(
SecurityConstants.GET_STACK_TRACE_PERMISSION);
}
// optimization so we do not call into the vm for threads that
// have not yet started or have terminated
if (!isAlive()) {
return EMPTY_STACK_TRACE;
}
StackTraceElement[][] stackTraceArray = dumpThreads(new Thread[]{this});
StackTraceElement[] stackTrace = stackTraceArray[0];
// a thread that was alive during the previous isAlive call may have
// since terminated, therefore not having a stacktrace.
if (stackTrace == null) {
stackTrace = EMPTY_STACK_TRACE;
}
return stackTrace;
} else {
// Don't need JVM help for current thread
return (new Exception()).getStackTrace();
}
}
/**
* 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() {
// check for getStackTrace permission
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(
SecurityConstants.GET_STACK_TRACE_PERMISSION);
security.checkPermission(
SecurityConstants.MODIFY_THREADGROUP_PERMISSION);
}
// Get a snapshot of the list of all threads
Thread[] threads = getThreads();
StackTraceElement[][] traces = dumpThreads(threads);
Map<Thread, StackTraceElement[]> m = new HashMap<>(threads.length);
for (int i = 0; i < threads.length; i++) {
StackTraceElement[] stackTrace = traces[i];
if (stackTrace != null) {
m.put(threads[i], stackTrace);
}
// else terminated so we don't put it in the map
}
return m;
}
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();
}
private native static StackTraceElement[][] dumpThreads(Thread[] threads);
private native static Thread[] getThreads();
/**
* 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;
}
/**
* 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 sun.misc.VM.toThreadState(threadStatus);
}
// 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) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(
new RuntimePermission("setDefaultUncaughtExceptionHandler")
);
}
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.
*
* @return the default uncaught exception handler for all threads
* @see #setDefaultUncaughtExceptionHandler
* @since 1.5
*/
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() {
return defaultUncaughtExceptionHandler;
}
/**
* 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.
*
* @return the uncaught exception handler for this thread
* @since 1.5
*/
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 JVM.
*/
private void dispatchUncaughtException(Throwable e) {
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 setPriority0(int newPriority);
private native void stop0(Object o);
private native void suspend0();
private native void resume0();
private native void interrupt0();
private native void setNativeName(String name);
}