前言
月是一轮明镜,晶莹剔透,代表着一张白纸(啥也不懂)
央是一片海洋,海乃百川,代表着一块海绵(吸纳万物)
泽是一柄利剑,千锤百炼,代表着千百锤炼(输入输出)
月央泽,学习的一种过程,从白纸->吸收各种知识->不断输入输出变成自己的内容
希望大家一起坚持这个过程,也同样希望大家最终都能从零到零,把知识从薄变厚,再由厚变薄!
一.Thread的作用:
直接看源码注释(我的翻译可能不太准,如果道友们有更棒的理解,可以留言或者私信)
/**
* 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.
* 1.thread是程序中的执行线程。 Java 虚拟机允许应用程序同时运行多个执行线程
* <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.
* 2.每个线程都有一个优先级。具有较高优先级的线程优先于具有较低优先级的线程执行。
* 每个线程可能也可能不会被标记为守护进程。当在某个线程中运行的代码创建一个新的Thread 对象时,
* 新线程的优先级最初设置为等于创建线程的优先级,并且当且仅当创建线程是守护进程时,新线程才是守护线程.
* <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).
* 3.当 Java 虚拟机启动时,通常会有一个非守护线程(通常调用某个指定类的名为 <code>main<code> 的方法)
*
* 4.Java 虚拟机继续执行线程,直到发生以下任一情况: exit类的 Runtime方法已被调用,
* 并且安全管理器已允许退出要进行的操作。所有不是守护线程的线程都已经死亡,要么是从对run方法的调用返回,
* 要么是抛出传播到run方法之外的异常
* 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.
* 5.有两种方法可以创建新的执行线程。
* 一种是将一个类声明为Thread的子类。这个子类应该覆盖Thread类的run方法。然后可以分配和启动子类的实例。
* 例如,计算大于规定值的素数的线程可以写成如下:
* class PrimeThread extends Thread {
* long minPrime;
* PrimeThread(long minPrime) {
* this.minPrime = minPrime;
* }
*
* public void run() {
* // compute primes larger than minPrime
*
* }
* }
* 下面的代码将创建一个线程并启动它运行 :
* PrimeThread p = new PrimeThread(143);
* * p.start();
*
* 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.
* 6.创建线程的另一种方法是声明一个实现Runnable接口的类。
* 然后该类实现run方法。然后可以分配类的实例,在创建 Thread时将其作为参数传递并启动。
* 其他样式中的相同示例如下所示:
* class PrimeRun implements Runnable {
* long minPrime;
* PrimeRun(long minPrime) {
* this.minPrime = minPrime;
* }
*
* public void run() {
* // compute primes larger than minPrime
*
* }
* }
* 下面的代码将创建一个线程并启动它运行:
* PrimeRun p = new PrimeRun(143);
* * new Thread(p).start();
* 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.
* 7.每个线程都有一个用于识别的名称。多个线程可能具有相同的名称。如果在创建线程时未指定名称,则会为其生成一个新名称
* <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.
* 8.除非另有说明,否则将null参数传递给此类中的构造函数或方法将导致抛出NullPointerException。
*/
二.类图:
三.成员变量:
//以下三个最初未初始化的字段由类 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 static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION =
new RuntimePermission("enableContextClassLoaderOverride");
private static final StackTraceElement[] EMPTY_STACK_TRACE
= new StackTraceElement[0];
/**
* 线程可以拥有的最低优先级。
*/
public final static int MIN_PRIORITY = 1;
/**
* 分配给线程的默认优先级
*/
public final static int NORM_PRIORITY = 5;
/**
* 线程可以拥有的最大优先级。
*/
public final static int MAX_PRIORITY = 10;
/*
* 此线程在可中断 IO 操作中被阻塞的对象(如果有)。设置此线程的中断状态后,应调用阻塞程序的中断方法。
*/
private volatile Interruptible blocker;
private final Object blockerLock = new Object();
/**
* 提供给当前调用 java.util.concurrent.locks.LockSupport.park 的参数。
* 由(私有)java.util.concurrent.locks.LockSupport.setBlocker 设置
* 使用 java.util.concurrent.locks.LockSupport.getBlocker 访问
*/
volatile Object parkBlocker;
private volatile String name;
private int priority;
private Thread threadQ;
private long eetop;
//是否单步执行此线程
private boolean single_step;
//线程是否为守护线程
private boolean daemon = false;
//JVM 状态
private boolean stillborn = false;
//将运行什么
private Runnable target;
//该线程组
private ThreadGroup group;
//此线程的上下文类加载器
private ClassLoader contextClassLoader;
//该线程继承的AccessControlContext
private AccessControlContext inheritedAccessControlContext;
//用于自动编号匿名线程
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
//与此线程有关的 ThreadLocal 值。该映射由 ThreadLocal 类维护。
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* //与此线程有关的 InheritableThreadLocal 值。该映射由 InheritableThreadLocal 类维护
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
/*
* 此线程请求的堆栈大小,如果创建者未指定堆栈大小,则为 0。
* 虚拟机可以用这个数字做任何它喜欢的事情;一些虚拟机会忽略它
*/
private long stackSize;
/*
* //在本机线程终止后持续存在的 JVM 私有状态
*/
private long nativeParkEventPointer;
/*
* Thread ID
*/
private long tid;
//用于生成线程 ID
private static long threadSeqNumber;
/*
* //工具的 Java 线程状态,已初始化以指示线程“尚未启动”
*/
private volatile int threadStatus = 0;
四.构造方法:
/**
* 1.分配一个新的Thread对象。此构造函数与 Thread(ThreadGroup,Runnable,String) Thread
* (null, null, gname) 效果相同,其中 gname 是新生成的名称。
* 自动生成的名称格式为 "Thread-"+n,其中n是一个整数。
*
*/
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
/**
* 1.分配一个新的Thread对象。此构造函数与Thread(ThreadGroup,Runnable,String)
* Thread (null, target, gname)效果相同,
* 其中 gname 是新生成的名称。自动生成的名称格式为"Thread-"+n,其中n是一个整数。.
*/
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
/**
* 创建一个继承给定 AccessControlContext 的新线程。这不是公共构造函数。
*/
Thread(Runnable target, AccessControlContext acc) {
init(null, target, "Thread-" + nextThreadNum(), 0, acc);
}
/**
* 分配一个新的Thread对象。
* 此构造函数与Thread(ThreadGroup,Runnable,String) Thread(group, target, gname)
* 具有相同的效果,其中 gname是新生成的名称。自动生成的名称格式为 "Thread-"+n,其中n是一个整数
*/
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
}
/**
* 分配一个新的 Thread对象。此构造函数与Thread(ThreadGroup,Runnable,String)
* Thread(null, null, name)具有相同的效果。
*/
public Thread(String name) {
init(null, null, name, 0);
}
/**
* 分配一个新的Thread对象。此构造函数与 Thread(ThreadGroup,Runnable,String)
* Thread(group, null, name)具有相同的效果。
*/
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
}
/**
* 分配一个新的Thread对象。此构造函数与Thread(ThreadGroup,Runnable,String)
* Thread(null, target, name)具有相同的效果。
*/
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
/**
* 1分配一个新的Thread对象,使其具有target作为其运行对象,具有指定的name作为其名称,
* 并且属于group所引用的线程组。
*2.如果有安全管理器,则调用其SecurityManager.checkAccess(ThreadGroup) 方法并使用 ThreadGroup 作为其参数。
*3.此外,当由覆盖getContextClassLoader或 setContextClassLoader的子类的构造函数直接或间接调用时,
* 其 checkPermission方法使用RuntimePermission("enableContextClassLoaderOverride")权限调用方法。
* 4.新创建的线程的优先级设置为等于创建它的线程的优先级,即当前运行的线程。
* 方法 setPriority可用于将优先级更改为新值。
*5.当且仅当创建它的线程当前被标记为守护线程时,新创建的线程最初被标记为守护线程。
* 方法 setDaemon可用于更改线程是否为守护进程。
*/
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
/**
* 1.分配一个新的Thread对象,使其以target为运行对象,以指定的name为名称,
* 并属于group引用的线程组,并具有指定的堆栈大小
* 2.此构造函数与 Thread(ThreadGroup,Runnable,String)相同,不同之处在于它允许指定线程堆栈大小。
* 堆栈大小是虚拟机要为此线程堆栈分配的地址空间的近似字节数。stackSize参数的影响(如果有)高度依赖于平台。
* 3.在某些平台上,为stackSize参数指定更高的值可能允许线程在抛出StackOverflowError之前实现更大的递归深度。
* 类似地,指定较低的值可能允许更多线程同时存在,而不会引发OutOfMemoryError(或其他内部错误)。
* stackSize参数的值与最大递归深度和并发级别之间的关系细节取决于平台。
* 在某些平台上,stackSize参数的值可能没有任何影响。
* 4.虚拟机可以自由地将stackSize参数视为建议。如果平台的指定值过低,
* 虚拟机可能会改为使用某些特定于平台的最小值;如果指定的值过高,
* 虚拟机可能会改为使用某些特定于平台的最大值。同样,
* 虚拟机可以随意向上或向下舍入它认为合适的指定值(或完全忽略它)
* 5.为 stackSize参数指定零值将导致此构造函数的行为与 Thread(ThreadGroup, Runnable, String)
* 构造函数完全相同。
* 6.由于此构造函数的行为具有平台相关性,因此在使用时应格外小心。执行给定计算所需的线程堆栈大小可能因 JRE 实现而异。
* 鉴于这种变化,可能需要仔细调整堆栈大小参数,并且可能需要针对要在其上运行应用程序的每个 JRE 实现重复调整
* 7.实施注意事项:鼓励 Java 平台实施者记录其与 stackSize 参数相关的实施行为。
*
*/
public Thread(ThreadGroup group, Runnable target, String name,
long stackSize) {
init(group, target, name, stackSize);
}
五.内部类:
caches
/** cache of subclass security audit results */
//1.子类安全审计结果的缓存
/* Replace with ConcurrentReferenceHashMap when/if it appears in a future
* release */
//2.如果它出现在未来版本中,则替换为 ConcurrentReferenceHashMap
private static class Caches {
/** cache of subclass security audit results */
//子类安全审计结果的缓存
static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
new ConcurrentHashMap<>();
/** queue for WeakReferences to audited subclasses */
//WeakReferences 到已审计子类的队列
static final ReferenceQueue<Class<?>> subclassAuditsQueue =
new ReferenceQueue<>();
}
state
/**
* 1.线程状态。线程可以处于以下状态之一:
* 1)new 尚未启动的线程处于此状态
* 2)runnable 在 Java 虚拟机中执行的线程处于这种状态
* 3)blocked 被阻塞等待监视器锁的线程处于这种状态。
* 4)waiting 无限期等待另一个线程执行特定操作的线程处于此状态
* 5)timed_waiting 等待另一个线程执行操作达指定等待时间的线程处于此状态
* 6)terminated 已退出的线程处于此状态
* 2.一个线程在给定的时间点只能处于一种状态。这些状态是虚拟机状态,不反映任何操作系统线程状态
*/
public enum State {
/**
* //尚未启动的线程的线程状态。
*/
NEW,
/**
* 可运行线程的线程状态。处于可运行状态的线程正在 Java 虚拟机中执行,
* 但它可能正在等待来自操作系统的其他资源,例如处理器
*/
RUNNABLE,
/**
* 线程阻塞等待监视器锁的线程状态。处于阻塞状态的线程正在等待监视器锁进入同步阻塞方法或
* 在调用 Object.wait()后重新进入同步阻塞方法
*/
BLOCKED,
/**
* 1.等待线程的线程状态。由于调用以下方法之一,线程处于等待状态
* 1)Object.wait(没有超时)
* 2)Thread.join(没有超时)
* 3)LockSupport.park()
*2.处于等待状态的线程正在等待另一个线程执行特定操作
* 3.例如,已在对象上调用Object.wait()的线程正在等待另一个线程调用Object.notify()
* 或 Object.notifyAll() 在那个对象上。调用 Thread.join()的线程正在等待指定的线程终止
*/
WAITING,
/**
* 具有指定等待时间的等待线程的线程状态。由于使用指定的正等待时间调用以下方法之一,线程处于定时等待状态:
* 1)Thread.sleep
* 2)Object.wait
* 3)Thread.join
* 4)LockSupport.parkNanos
* 5)LockSupport.parkUntil
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
* 终止线程的线程状态。线程已完成执行。
*/
TERMINATED;
}
uncaughtExceptionHandler
/**
* 1.当Thread由于未捕获的异常而突然终止时调用的处理程序接口。
* 2.当线程由于未捕获的异常而即将终止时,Java 虚拟机将使用 getUncaughtExceptionHandler查询线程的
* UncaughtExceptionHandler并将调用处理程序的uncaughtException方法,传递线程和异常作为参数。
* 3.如果一个线程没有明确设置它的UncaughtExceptionHandler,那么它的ThreadGroup对象作为它的
* UncaughtExceptionHandler。如果ThreadGroup对象对异常处理没有特殊要求,
* 可以将调用转发给getDefaultUncaughtExceptionHandler default uncaught exception handler。
*/
@FunctionalInterface
public interface UncaughtExceptionHandler {
/**
* 1.当给定线程由于给定的未捕获异常而终止时调用的方法
* 2.Java 虚拟机将忽略此方法抛出的任何异常。
*/
void uncaughtException(Thread t, Throwable e);
}
weakClassKey
/**
* Class 对象的弱键。
**/
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 实例,或者如果该对象的所指对象尚未清除,
* 如果给定对象是另一个 WeakClassKey 实例,该实例与该实例具有相同的非空引用对象,则返回 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;
}
}
}
六.内部方法:
sleep
/**
* 使当前正在执行的线程休眠(暂时停止执行)指定的毫秒数加上指定的纳秒数,
* 取决于系统计时器和调度程序的精度和准确性。该线程不会失去任何监视器的所有权
*/
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);
}
start
/**
* 1.使该线程开始执行; Java 虚拟机调用该线程的run方法。
* 2.结果是两个线程同时运行:当前线程(从调用start方法返回)和另一个线程(执行其run方法)。
* 3.多次启动一个线程是不合法的。特别是,线程一旦完成执行就可能不会重新启动。
*/
public synchronized void start() {
/**
* 1.不会为由 VM 创建的主方法线程或“系统”组线程调用此方法。将来添加到此方法的任何新功能也可能必须添加到 VM
* A zero status value corresponds to state "NEW".
* 2.零状态值对应于状态“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 */
}
}
}
run
/**
* 1.如果该线程是使用单独的Runnable运行对象构造的,则调用该Runnable对象的run方法;
* 否则,此方法不执行任何操作并返回
* 2.Thread的子类应该覆盖这个方法。
*/
@Override
public void run() {
if (target != null) {
target.run();
}
}
interrupt
/**
* 1.中断此线程
* 2.除非当前线程自己中断,这总是被允许的,否则会调用该线程的checkAccess() checkAccess方法,
* 这可能会导致抛出SecurityException
* 3.如果此线程在调用 Object.wait()、Object.wait(long) 或 Object.wait(long, int)
* 时被阻塞{Object} 类或 { join()}、{join(long)}、{join(long, int)}、{ sleep(long)} 的方法,
* 或者 {sleep(long, int)},这个类的方法,那么它的中断状态将被清除,它会收到一个{ InterruptedException}
* 4.如果此线程在 java.nio.channels.InterruptibleChannel上的 IO 操作中被阻塞,则通道将关闭,
* 线程的中断状态将被设置,线程将收到一个 java.nio .channels.ClosedByInterruptException。
* 5.如果此线程在 java.nio.channels.Selector中被阻塞,则该线程的中断状态将被设置,
* 并且它将立即从选择操作中返回,可能具有非零值,就像选择器的 java.nio.channels.Selector.wakeup 唤醒方法被调用。
* 6.如果前面的条件都不成立,则将设置此线程的中断状态
* 7.中断一个不活跃的线程不需要有任何影响
*/
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();
}
/**
* 1.测试当前线程是否被中断。通过该方法清除线程的中断状态。换句话说,如果这个方法被连续调用两次,
* 第二次调用将返回 false(除非当前线程再次被中断,在第一个调用清除其中断状态之后,第二个调用检查它之前)
* 2.由于线程在中断时不处于活动状态而被忽略的线程中断将通过此方法返回 false 来反映
*/
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
/**
* 1.测试此线程是否已被中断。线程的中断状态不受此方法影响。
* 2.由于线程在中断时不处于活动状态而被忽略的线程中断将通过此方法返回 false 来反映
*/
public boolean isInterrupted() {
return isInterrupted(false);
}
priority
/**
* 1.更改此线程的优先级
* 2.首先调用此线程的checkAccess方法,不带参数。这可能会导致抛出SecurityException
* 3.否则,该线程的优先级被设置为指定的newPriority和线程的线程组的最大允许优先级中的较小者
*/
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;
}
name
/**
* 1.将此线程的名称更改为等于参数name。
* 2.首先调用此线程的checkAccess方法,不带参数。这可能会导致抛出SecurityException
*/
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;
}
getThreadGroup
/**
* 返回该线程所属的线程组。如果此线程已死亡(已停止),则此方法返回 null。
*/
public final ThreadGroup getThreadGroup() {
return group;
}
activeCount
/**
* 1.返回当前线程的 java.lang.ThreadGroup 线程组
* 及其子组中活动线程数的估计值。递归迭代当前线程的线程组中的所有子组。
* 2.返回值只是一个估计值,因为该方法遍历内部数据结构时,线程数可能会动态变化,
* 并且可能会受到某些系统线程存在的影响。此方法主要用于调试和监视目的
*/
public static int activeCount() {
return currentThread().getThreadGroup().activeCount();
}
enumerate
/**
* 1.将当前线程的线程组及其子组中的每个活动线程复制到指定的数组中。
* 该方法只是调用当前线程的线程组的 java.lang.ThreadGroup.enumerate(Thread[])方法。
* 2.应用程序可能会使用activeCount方法来估计数组应该有多大,但是如果数组太短而无法容纳所有线程,
* 则额外的线程将被静默忽略。如果获取当前线程的线程组及其子组中的每个活动线程至关重要,
* 则调用者应验证返回的 int 值是否严格小于tarray 的长度
* 3.由于此方法固有的竞争条件,建议该方法仅用于调试和监视目的
*/
public static int enumerate(Thread tarray[]) {
return currentThread().getThreadGroup().enumerate(tarray);
}
join
/**
* 1.最多等待 millis毫秒让该线程死亡。 0超时意味着永远等待。
* 2.此实现使用以 this.isAlive为条件的 this.wait 调用循环。当线程终止时,
* 调用 this.notifyAll 方法。建议应用程序不要在Thread实例上使用wait、notify或 notifyAll。
*/
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;
}
}
}
/**
* 1.最多等待 millis毫秒加上nanos纳秒以使该线程死亡。
* 2.此实现使用以 this.isAlive为条件的 this.wait调用循环。当线程终止时,调用 this.notifyAll方法。
* 建议应用程序不要在 Thread实例上使用 wait、notify 或 notifyAll。
*/
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);
}
/**
* 1.等待这个线程死亡。
* 2.此方法的调用行为与调用完全相同
*/
public final void join() throws InterruptedException {
join(0);
}
dumpStack
/**
* 1.将当前线程的堆栈跟踪打印到标准错误流。此方法仅用于调试
*/
public static void dumpStack() {
new Exception("Stack trace").printStackTrace();
}
daemon
/**
* 1.将此线程标记为 isDaemon线程或用户线程。当唯一运行的线程都是守护线程时,Java 虚拟机退出
* 2.该方法必须在线程启动之前调用
*/
public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
/**
* 1.测试此线程是否为守护线程。
*/
public final boolean isDaemon() {
return daemon;
}
checkAccess
/**
* 1.确定当前运行的线程是否有权修改此线程
* 2.如果有一个安全管理器,它的checkAccess方法会以这个线程作为它的参数被调用。这可能会导致抛出SecurityException。
*/
public final void checkAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkAccess(this);
}
}
toString
/**
* 返回此线程的字符串表示形式,包括线程的名称、优先级和线程组。
*/
public String toString() {
ThreadGroup group = getThreadGroup();
if (group != null) {
return "Thread[" + getName() + "," + getPriority() + "," +
group.getName() + "]";
} else {
return "Thread[" + getName() + "," + getPriority() + "," +
"" + "]";
}
}
/**
* 1.返回此线程的上下文类加载器。上下文 ClassLoader 由线程的创建者提供,供在该线程中运行的代码在加载类和资源时使用。
* 如果不是setContextClassLoader,则默认为父线程的 ClassLoader 上下文。
* 原始线程的上下文类加载器通常设置为用于加载应用程序的类加载器
* 2.如果存在安全管理器,并且调用者的类加载器不是 null并且与上下文类加载器不同或不是其祖先,
* 则此方法调用安全管理器的SecurityManager.checkPermission(java.security. Permission)方法
*/
@CallerSensitive
public ClassLoader getContextClassLoader() {
if (contextClassLoader == null)
return null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader.checkClassLoaderPermission(contextClassLoader,
Reflection.getCallerClass());
}
return contextClassLoader;
}
/**
* 1.设置此线程的上下文类加载器。上下文ClassLoader可以在线程创建时设置,
* 并允许线程的创建者提供合适的类加载器,通过getContextClassLoader,在加载类和资源时在线程中运行代码
* 2.如果存在安全管理器,则使用RuntimePermission("setContextClassLoader")
* 权限调用其 SecurityManager.checkPermission(java.security.Permission)方法,
* 以查看是否设置上下文 ClassLoader允许
*/
public void setContextClassLoader(ClassLoader cl) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
}
contextClassLoader = cl;
}
getStackTrace
/**
* 1.返回表示此线程的堆栈转储的堆栈跟踪元素数组。如果此线程尚未启动、
* 已启动但尚未被系统安排运行或已终止,则此方法将返回一个零长度数组。
* 2.如果返回的数组长度不为零,则数组的第一个元素表示堆栈的顶部,这是序列中最近的方法调用。
* 数组的最后一个元素代表堆栈的底部,它是序列中最近的方法调用
* 3.如果有安全管理器,并且该线程不是当前线程,则调用安全管理器的checkPermission方法,
* 并带有RuntimePermission("getStackTrace")权限,看看是否可以获取堆栈跟踪
* 4.在某些情况下,某些虚拟机可能会从堆栈跟踪中省略一个或多个堆栈帧。
* 在极端情况下,允许没有与此线程相关的堆栈跟踪信息的虚拟机从此方法返回零长度数组。
*/
public StackTraceElement[] getStackTrace() {
if (this != Thread.currentThread()) {
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();
}
}
/**
* 1.返回所有活动线程的堆栈跟踪图。映射键是线程,每个映射值是一个StackTraceElement数组,表示相应Thread的堆栈转储
* 2.返回的堆栈跟踪采用为getStackTrace方法指定的格式
* 3.调用此方法时,线程可能正在执行。每个线程的堆栈轨迹仅代表一个快照,每个堆栈轨迹可能在不同的时间获得。
* 如果虚拟机没有关于线程的堆栈跟踪信息,则映射值中将返回一个长度为零的数组。
* to see if it is ok to get the stack trace of all threads.
* 4.如果有安全管理器,则使用RuntimePermission("getStackTrace")权限以及
* RuntimePermission("modifyThreadGroup")调用安全管理器的checkPermission方法
* 查看是否可以获取所有线程的堆栈跟踪的权限。
*/
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
//else 终止所以我们不把它放在地图上
}
return m;
}
getId
/**
* 返回此线程的标识符。线程 ID 是创建此线程时生成的正long数字。线程 ID 是唯一的,
* 并且在其生命周期内保持不变。当一个线程终止时,这个线程 ID 可能会被重用。
*/
public long getId() {
return tid;
}
getState
/**
* 返回此线程的状态。此方法设计用于监视系统状态,而不是用于同步控制。
*/
public State getState() {
// get current thread state
return sun.misc.VM.toThreadState(threadStatus);
}
set/getDefaultUncaughtExceptionHandler
/**
* 1.设置当线程由于未捕获的异常而突然终止时调用的默认处理程序,并且没有为该线程定义其他处理程序
* 2.未捕获的异常处理首先由线程控制,然后由线程的ThreadGroup对象控制,最后由默认的未捕获异常处理程序控制。
* 如果线程没有设置显式的未捕获异常处理程序,并且该线程的线程组(包括父线程组)没有专门化其uncaughtException方法,
* 则默认处理程序的uncaughtException方法将被调用。
* 3.通过设置默认的未捕获异常处理程序,应用程序可以为那些已经接受系统提供的任何“默认”行为的
* 线程更改处理未捕获异常的方式(例如记录到特定设备或文件)
* 4.请注意,默认的未捕获异常处理程序通常不应遵循线程的ThreadGroup对象,因为这可能会导致无限递归。
*/
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(
new RuntimePermission("setDefaultUncaughtExceptionHandler")
);
}
defaultUncaughtExceptionHandler = eh;
}
/**
* 返回当线程由于未捕获的异常而突然终止时调用的默认处理程序。如果返回值为null,则没有默认值。
*/
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
return defaultUncaughtExceptionHandler;
}
set/getUncaughtExceptionHandler
/**
* 返回当此线程由于未捕获的异常而突然终止时调用的处理程序。如果该线程没有明确设置未捕获的异常处理程序,
* 则返回该线程的ThreadGroup对象,除非该线程已终止,在这种情况下返回null
*/
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
/**
* 1.设置当该线程由于未捕获的异常而突然终止时调用的处理程序。
* 2.线程可以通过显式设置其未捕获的异常处理程序来完全控制它如何响应未捕获的异常。
* 如果没有设置这样的处理程序,则线程的ThreadGroup对象充当其处理程序
*/
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
checkAccess();
uncaughtExceptionHandler = eh;
}
processQueue
/**
* 从指定的映射中删除已在指定的引用队列中排队的任何键。
*/
static void processQueue(ReferenceQueue<Class<?>> queue,
ConcurrentMap<? extends
WeakReference<Class<?>>, ?> map)
{
Reference<? extends Class<?>> ref;
while((ref = queue.poll()) != null) {
map.remove(ref);
}
}
七.总结:
线程一直属于面试必备的重点,还需要继续深入...