/*
在某个线程中创建一个新线程,新线程的优先级和创建新线程的线程一致,如果创建线程是守护线程的话,则新线程
是守护线程。
当Java虚拟机启动时,通常有一个非守护线程(即main线程,调用指定类的main方法),Java虚拟机会继续执行这些线程
直到发生如下情形之一:
· 调用了类Runtime的exit()方法,并且安全管理器允许发生退出操作。
· 所有非守护线程均已死亡,可以是通过执行完run方法后返回,也可以是执行run方法时抛出了异常。
创建新的执行线程的两种方法:
· 声明一个Thread类的子类,子类中重写Thread类的run方法。
· 声明一个实现Runnable接口的类,类中实现run方法。
每个线程都有一个名字以供识别。线程名字可以相同。如果创建线程时未指定名字,会分配一个新名字。
除非特殊说明,否则将null参数传递给Thread类的构造器或者方法中会导致NullPointerException。
*/
public
class Thread implements Runnable {
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives();//本地方法
static {
registerNatives();
}
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; //JVM状态
/* 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;
/*
* 此线程请求的堆栈大小,如果创建者未指定堆栈大小,则为0。
* VM可以根据该编号执行*喜欢的任何操作;一些虚拟机将忽略它。
*/
private long stackSize; //线程栈大小
/*
* JVM-private state that persists after native thread termination.
* 本地线程终止后,JVM专用状态仍然存在。
*/
private long nativeParkEventPointer;
private long tid; //线程Id
private static long threadSeqNumber; //用于生成线程ID
private volatile int threadStatus = 0; //线程状态,初始化为0,默认不启动
private static synchronized long nextThreadID() { //返回一个线程Id
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;
/* 在可中断的I / O操作中阻塞该线程的对象(如果有)。设置此线程的中断状态后,应调用阻塞程序的中断方法。
*/
private volatile Interruptible blocker;
private final Object blockerLock = new Object();
/* 设置阻止字段;通过java.nio代码中的sun.misc.SharedSecrets调用
*/
void blockedOn(Interruptible b) {
synchronized (blockerLock) {
blocker = b;
}
}
public final static int MIN_PRIORITY = 1;//线程可以具有的最小优先级。
public final static int NORM_PRIORITY = 5;//分配给线程的默认优先级。
public final static int MAX_PRIORITY = 10;//线程可以具有的最大优先级。
public static native Thread currentThread();//本地方法,返回当前正在执行的线程对象的引用
/**
让当前正在执行的线程让出CPU,让给其他线程执行。但是注意,让步的线程并没有进入到阻塞,
而是提前回到就绪状态。
*/
public static native void yield(); //让出CPU,回到就绪状态
/**
*使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),
* 具体取决于系统定时器和调度程序的精度和准确性。 线程不会丢失任何显示器的所有权
*
* @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 native void sleep(long millis) throws InterruptedException;
/**
* 同上,可以加上纳秒数
*/
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);
}
/**
* Initializes a Thread with the current AccessControlContext.
* 使用当前的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 线程组
* @param target 调用run()方法的对象
* @param name 线程名
* @param stackSize 新线程的所需堆栈大小,0表示该参数将被忽略。
* @param acc 要继承的AccessControlContext;如果为null,则为 AccessController.getContext()
* @param inheritThreadLocals 如果为true,则从构造线程继承可继承线程局部变量的初始值
*/
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;//给线程名赋值
Thread parent = currentThread();//获取当前线程
SecurityManager security = System.getSecurityManager();//获取系统安全管理者
if (g == null) {
/* 如果有安全管理者, 先尝试获取安全管理者的线程组*/
if (security != null) {
g = security.getThreadGroup();
}
/* 如果此时线程组g还是null会采用当前线程的线程组。*/
if (g == null) {
g = parent.getThreadGroup();
}
}
//对线程组g进行检查
//主要检查:1.是否线程组为null 2.是否根线程组,如果是根线程组则要检查其是否有修改权限
g.checkAccess();
//权限检查:子类不能覆盖对安全性敏感的方法,否则将检查“enableContextClassLoaderOverride”运行时权限
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();//增加线程组中未启动线程的数量
this.group = g;//为线程组赋值
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);//设置线程优先级
//设置inheritableThreadLocals属性
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
this.stackSize = stackSize;//设置栈大小
tid = nextThreadID();//设置线程ID(此方法已加锁)
}
/**
* 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();
}
/**
* 分配一个新的Thread对象。 此构造具有相同的效果Thread (null, null, gname) ,
* 其中gname是新生成的名字。 自动生成的名称格式为"Thread-"+ n ,其中n为整数。
*/
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
/**
*分配一个新的Thread对象。 该构造函数具有与Thread (null, target, gname)相同的效果,
* 其中gname是新生成的名称。 自动生成的名称格式为"Thread-"+ n ,其中n为整数。
*
* @param target 指定启动此线程时调用其run方法的对象。 如果是null ,则这个线程的run方法被调用。
*/
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
/**
* Creates a new Thread that inherits the given AccessControlContext.
* This is not a public constructor.
* 创建一个继承自给定的AccessControlContext的新线程。 这不是公共构造函数。
*/
Thread(Runnable target, AccessControlContext acc) {
init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
}
/**
* 分配一个新的Thread对象。 此构造具有相同的效果Thread (group, target, gname) ,
* 其中gname是新生成的名字。 自动生成的名称格式为"Thread-"+ n ,其中n为整数。
*
* @param group
* 线程组。 如果是null并且有一个安全管理员,那么该组由SecurityManager.getThreadGroup()决定 。
* 如果没有安全管理员或SecurityManager.getThreadGroup()返回null ,该组将设置为当前线程的线程组。
* @param target
* 指定启动此线程时调用其run方法的对象。 如果是null ,则这个线程的run方法被调用。
* @throws SecurityException 如果当前线程不能在指定的线程组中创建线程
*/
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
}
/**
*分配一个新的Thread对象。 此构造具有相同的效果Thread (null, null, name) 。
* @param name 线程名
*/
public Thread(String name) {
init(null, null, name, 0);
}
/**
* 分配一个新的Thread对象。 此构造具有相同的效果Thread (group, null, name) 。
*
* @param group
* 线程组。 如果是null并且有一个安全管理员,那么该组由SecurityManager.getThreadGroup()决定 。
* 如果没有安全管理员或SecurityManager.getThreadGroup()返回null ,该组将设置为当前线程的线程组。
*
* @param name 线程的名字
*
* @throws SecurityException 如果当前线程不能在指定的线程组中创建线程
*/
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
}
/**
* 分配一个新的Thread对象。 此构造具有相同的效果Thread (null, target, name) 。
*
* @param target 指定启动此线程时调用其run方法的对象。 如果是null ,则这个线程的run方法被调用。
*
* @param name 线程名
*/
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
/**
*分配一个新的Thread对象,使其具有target作为其运行对象,具有指定的name作为其名称,
* 属于group引用的线程组。
* 如果有安全管理器,则使用ThreadGroup作为参数调用其checkAccess方法。
*
* 此外,它的checkPermission方法由RuntimePermission("enableContextClassLoaderOverride")权限调用,
* 直接或间接地由覆盖getContextClassLoader或setContextClassLoader方法的子类的getContextClassLoader
* setContextClassLoader调用。
*
* 新创建的线程的优先级设置为等于创建线程的优先级,即当前正在运行的线程。
* 可以使用方法setPriority将优先级改变为新值。
*
* 当且仅当创建它的线程当前被标记为守护线程时,新创建的线程才被初始化为守护线程。
* 方法setDaemon可以用于改变线程是否是守护进程。
*
*@param group
* 线程组。 如果是null并且有一个安全管理员,那么该组由SecurityManager.getThreadGroup()决定 。
* 如果没有安全管理员或SecurityManager.getThreadGroup()返回null ,该组将设置为当前线程的线程组。
*
* @param target 指定启动此线程时调用其run方法的对象。 如果是null ,则这个线程的run方法被调用。
*
* @param name 线程名
*
* @throws SecurityException 如果当前线程不能在指定的线程组中创建线程
*/
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
/**
* 分配一个新的Thread对象,以便它具有target作为其运行对象,将指定的name正如其名,
* 以及属于该线程组由称作group ,并具有指定的堆栈大小 。
* 这个构造函数与Thread(ThreadGroup,Runnable,String)相同,除了它允许指定线程栈大小的事实之外。
* 堆栈大小是虚拟机为该线程的堆栈分配的大致的地址空间字节数。
* stackSize参数的影响(如果有的话)与平台有关。
*
* 在某些平台上,指定了一个较高的值stackSize参数可以允许抛出一个前一个线程来实现更大的递归深
* 度StackOverflowError 。 类似地,指定较低的值可能允许更多数量的线程同时存在,而不会抛出
* OutOfMemoryError (或其他内部错误)。 所述stackSize参数的值和最大递归深度和并发水平之间
* 的关系的细节是依赖于平台的。 在某些平台上,该值stackSize参数可能没有任何效果。
*
* 虚拟机可以自由地对待stackSize参数作为建议。 如果平台的指定值不合理地低,虚拟机可能会改为
* 使用一些平台特定的最小值; 如果指定的值不合理地高,虚拟机可能会使用一些平台特定的最大值。
* 同样,虚拟机可以自由地按照合适的方式向上或向下舍入指定的值(或完全忽略它)。
*
* 对于指定的值为零stackSize参数将使这种构造的行为酷似Thread(ThreadGroup, Runnable, String)构造。
*
* 由于此构造函数的行为依赖于平台依赖性质,因此在使用时应特别小心。 执行给定计算所需的线程栈大小
* 可能会因JRE实现而异。 鉴于这种变化,可能需要仔细调整堆栈大小参数,并且可能需要对要运行应用程序
* 的每个JRE实现重复调整。
*
* 实现注意事项:鼓励Java平台实现者的记录其实施的行为stackSize参数。
*
* @param group
* 线程组。 如果是null并且有一个安全管理员,那么该组由SecurityManager.getThreadGroup()决定 。
* 如果没有安全管理员或SecurityManager.getThreadGroup()返回null ,该组将设置为当前线程的线程组。
*
* @param target 指定启动此线程时调用其run方法的对象。 如果是null ,则这个线程的run方法被调用。
*
* @param name 线程名
*
* @param stackSize 新线程所需的堆栈大小,或为零表示此参数将被忽略。
*
* @throws SecurityException 如果当前线程不能在指定的线程组中创建线程
*
* @since 1.4
*/
public Thread(ThreadGroup group, Runnable target, String name,
long stackSize) {
init(group, target, name, stackSize);
}
/**
*调用此方法,这个线程开始执行,jvm虚拟机会调用run()方法
* 一个线程被启动多次是不合法的
* 特别是,线程一旦完成执行就可能不会重新启动。
*
* @exception IllegalThreadStateException 如果线程已经启动过
* @see #run()
* @see #stop()
*/
public synchronized void start() {
/**
*VM创建/设置的主方法线程或“系统”组线程不会调用此方法。将来可能会向该方法添加任何添加到此方法的新功能。
* 零状态值对应于状态“ 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) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack
不做什么。如果start0抛出了Throwable,则它将被向上传递到调用堆栈*/
}
}
}
private native void start0();//本地方法
/**
* 如果这个线程是使用另外的Runnable对象构造的,那么调用的是这个Runnable对象的run方法;
* 否则,此方法不执行任何操作并返回。
* Thread的子类应该重写此方法
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
if (target != null) {
target.run();
}
}
/**
* 系统调用此方法,以使线程有机会在线程实际退出之前进行清理
*/
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;
}
/**
* 强制线程停止执行
* 如果安装了一个安全管理器,它的checkAccess方法this作为参数。 这可能导致SecurityException被提升(在当前线程中)。
* 如果此线程与当前线程不同(即当前线程正试图停止除本身线程之外的线程),则另外还调用安全管理器的checkPermission
* 方法(具有RuntimePermission("stopThread")参数)。 再次,这可能会导致抛出SecurityException (在当前线程中)。
* 由该线程表示的线程被强制停止,它正在异常进行,并抛出一个新创建的ThreadDeath对象
* 允许停止尚未启动的线程。
* 如果线程最终启动,则它立即终止。
* <p>
* 一个应用程序通常不应该尝试捕获ThreadDeath ,除非它必须做一些非凡的清理操作(请注意,抛出ThreadDeath导致
* finally语句try语句在线程正式死亡之前执行)。 如果一个catch子句捕获一个ThreadDeath对象,重要的是重新抛出
* 该对象,使线程实际上死亡。
*对未捕获的异常做出反应的顶级错误处理程序不会打印出消息,或者如果未捕获的异常是ThreadDeath 的实例,
* 则不会通知应用程序。
*
* @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 这种方法本质上是不安全的. 使用Thread.stop停止线程会导致它解锁
* 所有已锁定的监视器(由于未经检查的ThreadDeath异常会在堆栈中传播)。
* 如果先前由这些监视器保护的任何对象处于不一致状态,则损坏的对象将变为其他
* 线程可见,从而可能导致任意行为。 stop 的许多用法都应替换为仅修改某些变量
* 以指示目标线程应停止运行的代码。 目标线程应定期检查此变量,如果该变量指示
* 要停止运行,则应有序地从其运行方法返回。 如果目标线程等待很长时间(例如,
* 在条件变量上),则应使用 interrupt 方法来中断等待。
* 有关更多信息,请参见
* <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">
* 为什么不赞成使用Thread.stop,Thread.suspend和Thread.resume?</a>.
*/
@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 零状态值对应于“ NEW”,它不能更改为
// not-NEW because we hold the lock. not-NEW,因为我们持有锁
if (threadStatus != 0) {
resume(); //唤醒被挂起的线程
}
// The VM can handle all thread states VM可以处理所有线程状态
stop0(new ThreadDeath());
}
@Deprecated
public final synchronized void stop(Throwable obj) {
throw new UnsupportedOperationException();
}
/**
* 中断此线程。
*
* <p> 除非当前线程正在中断自身, 这是始终允许的,所以当调用此线程的checkAccess方法,
* 可能会导致抛出SecurityException 。
*
* <p> 如果线程在调用这个类的{@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)},
* 这些方法时被阻塞, 那么它的中断状态将被清除,并且将收到一个InterruptedException 。
*
* <p> 如果这个线程在 {@link java.nio.channels.InterruptibleChannel InterruptibleChannel}
* I/O操作时被阻塞,然后通道将会关闭,线程的中断状态将被设置,
* 并且该线程将收到一个 {@link java.nio.channels.ClosedByInterruptException}.
*
* <p>如果此线程在{@link java.nio.channels.Selector}中被阻塞,则该线程的中断状态将被设置,
* 并且它将立即从选择操作中返回,并可能返回非零值,就像选择器的
* {调用@link java.nio.channels.Selector#wakeup唤醒}方法。
*
* <p> 如果上述条件均不成立,则将设置该线程的中断状态。 </p>
*
* <p> 中断未激活的线程不会产生任何效果。
*
* @throws SecurityException 如果当前线程无法修改此线程
*
* @revised 6.0
* @spec JSR-51
*/
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // 只是设置中断标志
b.interrupt(this);
return;
}
}
interrupt0();
}
/**
* 测试当前线程是否已被中断。 通过此方法可以清除线程的中断状态。 换一种说法
* 换句话说,如果这个方法被连续调用两次,那么第二个调用将返回false
* (除非当前线程再次中断,在第一个调用已经清除其中断状态之后,在第二个调用之前已经检查过)。
*
*忽略线程中断,因为线程在中断时不存在将被该方法返回false所反映。
* @return <code>true</code> if the current thread has been interrupted;
* <code>false</code> otherwise.
* @see #isInterrupted()
* @revised 6.0
*/
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
/**
* 测试当前线程是否已被中断。 通过此方法可以清除线程的中断状态。
*
* 忽略线程中断,因为线程在中断时不存在将被该方法返回false所反映。
*
* @return <code>true</code> if this thread has been interrupted;
* <code>false</code> otherwise.
* @see #interrupted()
* @revised 6.0
*/
public boolean isInterrupted() {
return isInterrupted(false);
}
/**
* 测试某些线程是否已被中断。根据传递的ClearInterrupted的值,重置或不重置中断状态。
*/
private native boolean isInterrupted(boolean ClearInterrupted);
/**
* Throws {@link NoSuchMethodError}.
*
* @deprecated 这种方法最初是为了销毁这个线程而没有任何清理。 它所持有的任何监视器
* 都将保持锁定。 但是,该方法从未实现。 如果要实施,那么它将是suspend()的方式是僵
* 死的 。 如果目标线程在销毁时保护关键系统资源的锁,则无法再次访问该资源。 如果另
* 一个线程曾尝试锁定此资源,将导致死锁。 这种僵局通常表现为“冻结”过程。
* @throws NoSuchMethodError always
*/
@Deprecated
public void destroy() {
throw new NoSuchMethodError();
}
/**
* 测试此线程是否仍然存在。如果一个线程已经启动并且尚未死亡,则该线程是活动的。
*/
public final native boolean isAlive();
/**
* 挂起该线程。
* 首先,这个线程的checkAccess方法被调用,没有参数。 这可能会导致SecurityException (在当前线程中)。
* 如果线程活着,它将被暂停,并且不会进一步进行,除非和直到恢复。
* @deprecated 这种方法已被弃用,因为它本身就是死锁的。 如果目标线程在挂起时保护关键系统资源的
* 监视器上的锁定,则在目标线程恢复之前,线程不能访问该资源。 如果要恢复目标线程的线程在调用
* resume之前尝试锁定此监视器, resume导致死锁。 这种僵局通常表现为“冻结”过程。
*/
@Deprecated
public final void suspend() {
checkAccess();
suspend0();
}
/**
* 恢复被挂起的线程。
* @deprecated 此方法仅适用于suspend() ,由于suspend()有死锁倾向已经被放弃,因此该方法也被弃用。
*/
@Deprecated
public final void resume() {
checkAccess();
resume0();
}
/**
* 修改此线程的优先级。
*/
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) {//判断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;
}
/**
* 返回当前线程的thread group及其子组中活动线程数的估计。 递归地遍历当前线程的线程组中的所有子组。
* 返回的值只是一个估计,因为线程数可能会在此方法遍历内部数据结构时动态更改,并且可能受某些系统线
* 程的存在的影响。 此方法主要用于调试和监视。
*/
public static int activeCount() {
return currentThread().getThreadGroup().activeCount();
}
/**
*将当前线程的线程组及其子组中的每个活动线程复制到指定的数组中。
* 这个方法简单地调用当前线程的线程组的ThreadGroup.enumerate(Thread[])方法。
* 应用程序可能会使用activeCount方法来估计数组的大小,但是如果数组太短而不能容
* 纳所有线程,则会忽略额外的线程。 如果在当前线程组及其子组中获取每个活动线程至关重要,
* 则调用者应验证返回的int值是否严格小于tarray的长度。
*
* 由于本方法中内在的竞争条件,建议该方法仅用于调试和监控。
*/
public static int enumerate(Thread tarray[]) {
return currentThread().getThreadGroup().enumerate(tarray);
}
/**
* 返回此线程中的堆栈帧数。此线程必须被挂起。
* @deprecated 这个方法的调用依赖于被放弃的suspend()方法,此外,该方法调用的结果从未明确定义
*/
@Deprecated
public native int countStackFrames();
/**
*令当前线程进入阻塞状态,让调用此方法的线程对象运行millis毫秒
* 此实现使用this.wait调用的循环,条件为this.isAlive 。 当线程终止时,调用this.notifyAll方法。
* 建议应用程序不使用wait , notify ,或notifyAll上Thread实例。
*/
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);//等待delay毫秒
now = System.currentTimeMillis() - base;
}
}
}
/**
* 令当前线程进入阻塞状态,让调用此方法的线程对象运行millis毫秒+nanos纳秒
*/
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 static void dumpStack() {
new Exception("Stack trace").printStackTrace();
}
/**
* 将此线程标记为daemon线程或用户线程。 当运行的唯一线程都是守护进程线程时,Java虚拟机将退出。
* 必须在线程启动之前调用此方法。
*/
public final void setDaemon(boolean on) {
checkAccess();//确认当前线程是否具有修改的权限
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
/**
* 测试此线程是否是守护程序线程。
*/
public final boolean isDaemon() {
return daemon;
}
/**
* 确定当前正在运行的线程是否具有修改此线程的权限。
* 如果有一个安全管理器,它的checkAccess方法被调用并且以这个线程作为它的参数。 这可能会导致投掷SecurityException 。
*/
public final void checkAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkAccess(this);
}
}
/**
* 返回此线程的字符串表示,包括线程的名称,优先级和线程组。
*/
public String toString() {
ThreadGroup group = getThreadGroup();
if (group != null) {
return "Thread[" + getName() + "," + getPriority() + "," +
group.getName() + "]";
} else {
return "Thread[" + getName() + "," + getPriority() + "," +
"" + "]";
}
}
/**
* 返回这个线程的上下文类加载器。上下文类加载器由线程的创建者提供
* 以便在加载类和资源时在此线程中运行的代码使用。如果没有调用setContextClassLoader()
* 方法来设置,默认是父线程的上下文类加载器,通常将原始线程的上下文ClassLoader设置为
* 用于加载应用程序的类加载器
*
* 如果安全管理器存在,并且调用者的类加载器不是null ,并且与上下文类加载器的祖先不
* 一样或者祖先,则该方法调用安全管理器的checkPermission方法,具有RuntimePermission
* ("getClassLoader")权限,以验证是否检索上下文类加载器是允许的。
*
* @return 此线程的上下文ClassLoader,或{@code null} 指示系统类加载器(否则,引导类加载器)
*
* @throws SecurityException 如果当前线程无法获取上下文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;
}
/**
* 设置此线程的上下文ClassLoader。可以在创建线程时设置上下文ClassLoader,
* 并允许线程的创建者通过{@code getContextClassLoader}提供适当的类加载器,
* 以便在加载类和资源时在线程中运行代码。
*
* 如果存在安全管理员,则其checkPermission方法将被调用RuntimePermission
* ("setContextClassLoader")权限,以查看是否允许设置上下文ClassLoader。
*
* @param cl 此线程的上下文ClassLoader,或者为null,指示系统类加载器(否则,为引导类加载器)
*
* @throws SecurityException 如果当前线程无法设置上下文ClassLoader
*
* @since 1.2
*/
public void setContextClassLoader(ClassLoader cl) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
}
contextClassLoader = cl;
}
/**
* 当且仅当当前线程在指定对象上持有监视器锁时,才返回true。
*
* <p>此方法旨在允许程序断言当前线程已持有指定的锁:
* <pre>
* assert Thread.holdsLock(obj);
* </pre>
*
* @param obj 测试锁所有权的对象
* @throws NullPointerException if obj is <tt>null</tt>
* @return <tt>true</tt> 如果当前线程将监视器锁保持在指定对象上。
* @since 1.4
*/
public static native boolean holdsLock(Object obj);
private static final StackTraceElement[] EMPTY_STACK_TRACE
= new StackTraceElement[0];
/**
* 返回表示此线程的堆栈转储的堆栈跟踪元素数组。 该方法将返回一个零长度的数组,
* 如果该线程尚未启动,已启动但尚未被计划运行,或已终止。 如果返回的数组非零长度,
* 则数组的第一个元素表示堆栈的顶部,这是序列中最近的方法调用。 数组的最后一个元
* 素表示堆栈的底部,这是序列中最近最少的方法调用。
* 如果有一个安全管理器,并且这个线程不是当前的线程,那么安全管理器的checkPermission
* 方法被调用一个RuntimePermission("getStackTrace")权限来查看是否可以获取堆栈跟踪。
*
* 在某些情况下,某些虚拟机可能从堆栈跟踪中省略一个或多个堆栈帧。 在极端情况下,
* 允许没有关于该线程的堆栈跟踪信息的虚拟机从该方法返回零长度数组。
*
* @return 返回一个StackTraceElement的数组,每个表示一个堆栈帧。
*
* @throws SecurityException 如果安全管理器存在并且其checkPermission方法不允许获取线程的堆栈跟踪。
* @see SecurityManager#checkPermission
* @see RuntimePermission
* @see Throwable#getStackTrace
*
* @since 1.5
*/
public StackTraceElement[] getStackTrace() {
if (this != Thread.currentThread()) {
// 检查getStackTrace权限
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(
SecurityConstants.GET_STACK_TRACE_PERMISSION);
}
// 优化,因此我们不会针对尚未启动或已终止的线程调用vm
if (!isAlive()) {
return EMPTY_STACK_TRACE;
}
StackTraceElement[][] stackTraceArray = dumpThreads(new Thread[] {this});
StackTraceElement[] stackTrace = stackTraceArray[0];
// 在上一个isAlive调用期间处于活动状态的线程可能已终止,因此没有堆栈跟踪。
if (stackTrace == null) {
stackTrace = EMPTY_STACK_TRACE;
}
return stackTrace;
} else {
// Don't need JVM help for current thread
return (new Exception()).getStackTrace();
}
}
/**
* 返回所有活动线程的堆栈跟踪的映射。
* 映射键是线程,每个映射值都是StackTraceElement的数组,该数组表示相应 Thread的堆栈转储。
* 返回的堆栈跟踪采用针对{@link #getStackTrace getStackTrace}方法指定的格式。
*
* <p>调用此方法时,线程可能正在执行。
* 每个线程的堆栈跟踪仅表示快照,并且可以在不同时间获取每个堆栈跟踪。
* 如果虚拟机没有关于线程的堆栈跟踪信息,则将在地图值中返回零长度的数组。
*
* 如果有一个安全管理员,那么安全管理员的checkPermission方法被调用一个
* RuntimePermission("getStackTrace")权限以及RuntimePermission("modifyThreadGroup")
* 权限来查看是否可以获取所有线程的堆栈跟踪
*
* @throws SecurityException 如果安全管理器存在并且其 checkPermission 方法不允许获取线程的堆栈跟踪。
* @see #getStackTrace
* @see SecurityManager#checkPermission
* @see RuntimePermission
* @see Throwable#getStackTrace
*
* @since 1.5
*/
public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
// 检查getStackTrace权限
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(
SecurityConstants.GET_STACK_TRACE_PERMISSION);
security.checkPermission(
SecurityConstants.MODIFY_THREADGROUP_PERMISSION);
}
// 获取所有线程列表的快照
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);
}
// 否则终止了,所以我们不把它放在地图上
}
return m;
}
private static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION =
new RuntimePermission("enableContextClassLoaderOverride");
/** 子类安全审核结果的缓存 */
/* 如果它在将来的版本中出现,请用ConcurrentReferenceHashMap替换 */
private static class Caches {
/** 子类安全审核结果的缓存 */
static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
new ConcurrentHashMap<>();
/** 排队等待对已审计子类的弱引用 */
static final ReferenceQueue<Class<?>> subclassAuditsQueue =
new ReferenceQueue<>();
}
/**
* 验证可以构造此(可能是子类)实例而不会违反安全性约束:
* 子类不得覆盖对安全性敏感的非最终方法,否则,请检
* 查“ enableContextClassLoaderOverride” RuntimePermission。
*/
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();
}
/**
* 对给定的子类执行反射检查,以验证它不会覆盖对安全敏感的非最终方法。
* 如果子类重写任何方法,则返回true,否则返回false。
*/
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();
/**
* 返回此线程的id
*/
public long getId() {
return tid;
}
/**
*线程状态。线程可以处于以下六种状态之一:
* <ul>
* <li>{@link #NEW}<br>
* 尚未启动的线程处于此状态。
* </li>
* <li>{@link #RUNNABLE}<br>
* 在Java虚拟机中执行的线程处于这种状态。
* </li>
* <li>{@link #BLOCKED}<br>
* 等待监视器锁而被阻塞的线程处于此状态.
* </li>
* <li>{@link #WAITING}<br>
* 无限期地等待另一个线程执行特定操作的线程处于此状态。
* </li>
* <li>{@link #TIMED_WAITING}<br>
* 正在等待另一个线程执行操作的线程最多达到指定的等待时间,该线程处于此状态。
* </li>
* <li>{@link #TERMINATED}<br>
* 退出的线程处于此状态。
* </li>
* </ul>
*
* <p>
* 在给定的时间点,线程只能处于一种状态。这些状态是虚拟机状态,不反映任何操作系统线程状态。
*
* @since 1.5
* @see #getState
*/
public enum State {
/**
* 尚未启动的线程的线程状态。
*/
NEW,
/**
* 可运行线程的线程状态。处于可运行状态的线程正在Java虚拟机中执行,
* 但它可能正在等待来自操作系统(例如处理器)的其他资源。
*/
RUNNABLE,
/**
* 处于阻塞状态的线程正在等待监视器锁进入同步块/方法
*/
BLOCKED,
/**
*等待线程的线程状态 由于调用以下方法之一,线程处于等待状态:
* Object.wait没有超时
* Thread.join没有超时
* LockSupport.park
* 等待状态的线程正在等待另一个线程执行特定的动作。 例如,
* 已经在对象上调用Object.wait()线程正在等待另一个线程调用该对象上Object.notify()
* Object.notifyAll()或。 调用Thread.join()的线程正在等待指定的线程终止。
*/
WAITING,
/**
*具有指定等待时间的等待线程的线程状态。 线程处于定时等待状态,因为在指定的正等待时间内调用以下方法之一:
* Thread.sleep
* Object.wait与超时
* Thread.join与超时
* LockSupport.parkNanos
* LockSupport.parkUntil
*/
TIMED_WAITING,
/**
* 终止线程的线程状态。
* 线程已完成执行.
*/
TERMINATED;
}
/**
* 返回此线程的状态。
*/
public State getState() {
// 获取当前线程状态
return sun.misc.VM.toThreadState(threadStatus);
}
// Added in JSR-166
/**
* 当线程由于未捕获的异常突然终止时调用的处理程序的接口。
* 当线程由于未捕获的异常而终止时,Java虚拟机将使用* {@link #getUncaughtExceptionHandler}查询线程的
* UncaughtExceptionHandler,并将调用处理程序的 uncaughtException 方法,将线程和异常作为参数传递。
* 如果未明确设置线程的UncaughtExceptionHandler ,则其ThreadGroup对象将作为其UncaughtExceptionHandler 。
* 如果ThreadGroup对象对处理异常没有特殊要求,它可以将调用转发给{@linkplain #getDefaultUncaughtExceptionHandler
* 默认未捕获的异常处理程序}
* @see #setDefaultUncaughtExceptionHandler
* @see #setUncaughtExceptionHandler
* @see ThreadGroup#uncaughtException
* @since 1.5
*/
@FunctionalInterface
public interface UncaughtExceptionHandler {
/**
* 当给定线程由于给定的未捕获异常而终止时调用的方法。
* Java虚拟机将忽略此方法引发的任何异常。
* @param t the thread
* @param e the exception
*/
void uncaughtException(Thread t, Throwable e);
}
// 除非明确设置,否则为null
private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
// 除非明确设置,否则为null
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
/**
* 设置当线程由于未捕获的异常而突然终止并且尚未为该线程定义其他处理程序时调用的默认处理程序。
*
* <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;
}
/**
* 返回由于未捕获的异常而导致线程突然终止时调用的默认处理程序。如果返回值为 null则没有默认值。
* @since 1.5
* @see #setDefaultUncaughtExceptionHandler
* @return 所有线程的默认未捕获异常处理程序
*/
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
return defaultUncaughtExceptionHandler;
}
/**
* 返回由于未捕获的异常而导致该线程突然终止时调用的处理程序。
* 如果此线程没有显式设置未捕获的异常处理程序,则将返回该线程的ThreadGroup对象,
* 除非该线程已终止,在这种情况下将返回null。
* @since 1.5
* @return 此线程的未捕获异常处理程序
*/
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
/**
*设置当此线程由于未捕获的异常而突然终止时调用的处理程序。
* <p>通过显式设置其未捕获的异常处理程序,线程可以完全控制其对未捕获的
* 异常的响应。如果未设置此类处理程序,则由线程的ThreadGroup对象将充当其处理程序。
* @param eh 用作此线程的未捕获异常处理程序的对象。如果为null,则此线程没有显式处理程序。
* @throws SecurityException 如果不允许当前线程修改此线程抛出此异常。
* @see #setDefaultUncaughtExceptionHandler
* @see ThreadGroup#uncaughtException
* @since 1.5
*/
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
checkAccess();
uncaughtExceptionHandler = eh;
}
/**
* 向处理程序调度一个未捕获的异常。 此方法只能由JVM调用。
*/
private void dispatchUncaughtException(Throwable e) {
getUncaughtExceptionHandler().uncaughtException(this, e);
}
/**
* 从指定映射中移除已在指定参考队列上排队的所有键。
*/
static void processQueue(ReferenceQueue<Class<?>> queue,
ConcurrentMap<? extends
WeakReference<Class<?>>, ?> map)
{
Reference<? extends Class<?>> ref;
while((ref = queue.poll()) != null) {
map.remove(ref);
}
}
/**
* 类对象的弱键。
**/
static class WeakClassKey extends WeakReference<Class<?>> {
/**
* 用来保存引用者身份哈希码值,以确保在清除引用者后保持一致的哈希码
*/
private final int hash;
/**
* 为给定对象创建一个新的WeakClassKey,并在队列中注册.
*/
WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
super(cl, refQueue);
hash = System.identityHashCode(cl);
}
/**
* 返回对象的哈希码。
*/
@Override
public int hashCode() {
return hash;
}
/**
* 如果给定对象是相同的WeakClassKey实例,则返回true,
* 或者如果尚未清除该对象的引用,则如果给定对象是另一个WeakClassKey实例,
* 且具有与此对象相同的非null引用,则返回true。
*/
@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;
}
}
}
// 以下三个最初未初始化的字段仅由类java.util.concurrent.ThreadLocalRandom管理。
// 这些字段用于在并发代码中构建高性能PRNG,因此我们不会冒意外的错误共享的风险。
// 因此,这些字段用@Contended隔离。
/** ThreadLocalRandom的当前种子 */
@sun.misc.Contended("tlr")
long threadLocalRandomSeed;
/** 探针哈希值;如果threadLocalRandomSeed初始化,则为非零 */
@sun.misc.Contended("tlr")
int threadLocalRandomProbe;
/** 从公共ThreadLocalRandom序列中分离出的次要种子*/
@sun.misc.Contended("tlr")
int threadLocalRandomSecondarySeed;
/* 一些私有本地方法 */
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);
}
Thread
最新推荐文章于 2021-03-30 23:07:01 发布