一、简单使用
@Test
public void ThreadTest() throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("开启线程名称 :"+Thread.currentThread().getName());
}
});
thread.start();
System.out.println("主线程名称:"+Thread.currentThread().getName());
Thread.sleep(100);
}
运行效果:
二、源码
Ⅰ、类说明
- 一个 thread 是程序中的执行线程,Java 虚拟机允许一个应用同时执行多个线程
- 每一个线程都有一个优先级。具有较高优先级的线程优先于较低优先级的线程执行
- 每个线程可能会,也可能不会被标记为一个守护程序(daemon)
- 当在某个线程中运行的代码创建性的 Thread 对象时,新线程的优先级最初设置为等于创建线程的有限即,若创建的线程是 一个守护线程,那么被创建的线程也是一个守护线程(说白了,新线程的优先级、是否为守护线程 就是“子随父”)
- 当 Java 虚拟机启动时,通常有一个非守护线程(通常调用指定类的 main 方法),Java 虚拟机继续执行直到发生以下任何一种情况:
① 调用类 Runtime 的 exit方法,并且安全管理器已允许进行退出操作
② 所有的非守护线程都已经消亡,要么通过调用返回到 run 方法,要么抛出传播到 run 方法之外的异常(注意:这里指的是个线程抛出异常,其它线程捕获异常,与我们平时在编码时的同一线程内是不一样的) - 这里有两种方式去创建一个新的线程执行。第一种方式是声明一个类成为 Thread 的子类,这个子类应该重写 run 方法第二种方式是声明一个类,并实现 Runnable 接口,然后这个类实现 run 方法
- 每个线程都有一个名字供识别,一个以上的线程可能具有相同的名称。如果在创建线程时未指定名称,则会为其生成一个新的名称
- 除非另有说明,否则将 null 参数传递给此类(这里特指 Thread)中的构造函数或方法将引发空指针异常
Ⅱ、类结构说明
Ⅲ、属性声明
/* Make sure registerNatives is the first thing <clinit> does. */
//确保 registerNatives 是第一件要做的事情(看命名可以推测,应当是本地注册,这里使用了 native 修饰符)
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 */
//JVM 状态
private boolean stillborn = false;
/* What will be run. */
//将要运行的内容
private Runnable target;
/* The group of this thread */
//这个线程所属的线程组
private ThreadGroup group;
/* The context ClassLoader for this thread */
// 线程的上下文加载器
private ClassLoader contextClassLoader;
/* The inherited AccessControlContext of this thread */
// 这个线程继承的 AccessControlContext (访问控制上下文对象)
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值 该映射由 ThreadLocal 类维护
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
//与此线程有关的 InheritableThreadLocal 值,该映射由InheritableThreadLocal 类维护
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
/*
* The requested stack size for this thread, or 0 if the creator did
* not specify a stack size. It is up to the VM to do whatever it
* likes with this number; some VMs will ignore it.
*/
// 此线程请求的堆栈大小,如果创建者未指定堆栈大小,则为0.由虚拟机决定使用此编号执行任何操作。
//一些虚拟机将忽略它
private long stackSize;
/*
* JVM-private state that persists after native thread termination.
*/
// JVM私有状态在本地线程终止后仍然存在
private long nativeParkEventPointer;
/*
* Thread ID
*/
//线程id
private long tid;
/* For generating thread ID */
// 用于生成线程 id
private static long threadSeqNumber;
/* Java thread status for tools,
* initialized to indicate thread 'not yet started'
*/
// Java 线程状态工具,初始化后指示线程“尚未启动”
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
*/
// 提供给 java.util.concurrent.locks.LockSupport.park. 的当前调用的参数
// 由私有 java.util.concurrent.locks.LockSupport.setBlocker 设置
// 使用 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.
*/
//在可中断的I/O操作中阻塞该线程的对象(如果有),设置此线程的中断状态后,应调用阻塞程序的中断方法
private volatile Interruptible blocker;
private final Object blockerLock = new Object();
/* Set the blocker field; invoked via sun.misc.SharedSecrets from java.nio code
*/
//设置阻止字段;通过 java.nio 代码中的 sun.misc.SharedSecrets
void blockedOn(Interruptible b) {
synchronized (blockerLock) {
blocker = b;
}
}
/**
* The minimum priority that a thread can have.
*/
//线程拥有的最低优先级
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
//线程默认优先级
public final static int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
//线程最高优先级
public final static int MAX_PRIORITY = 10;
Ⅳ、Thread 内的方法和内部类说明
/**
* Returns a reference to the currently executing thread object.
*
* @return the currently executing thread.
*/
// 返回当前执行线程对象的引用
public static native Thread currentThread();
/**
* A hint to the scheduler that the current thread is willing to yield
* its current use of a processor. The scheduler is free to ignore this
* hint.
*
* <p> Yield is a heuristic attempt to improve relative progression
* between threads that would otherwise over-utilise a CPU. Its use
* should be combined with detailed profiling and benchmarking to
* ensure that it actually has the desired effect.
*
* <p> It is rarely appropriate to use this method. It may be useful
* for debugging or testing purposes, where it may help to reproduce
* bugs due to race conditions. It may also be useful when designing
* concurrency control constructs such as the ones in the
* {@link java.util.concurrent.locks} package.
*/
/**
* 给调度程序提示,当前线程愿意放弃当前使用的处理器,调度程序可以随意忽略此提示
* Yield 是一种启发式尝试,旨在提高线程之间的执行,否则将过渡利用 CPU。 因将其使用的性能分析和基准测试结合起来
* 已确保它实际上具有所需的效果。
* 很少适合使用此方法。对于调式或测试目的,它可能有用,因为它可能有助于重现由于竞争条件而产生的错误。当设计者
* 诸如 java.util.concurrent.locks 包中的并发控制结构时,它也可能很有用
* 说白了,这个方法就是主动让出 CPU 资源,但是需要注意的是:在让出CPU资源后,仍有可能再次执行这个线程
*/
public static native void yield();
/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
*
* @param millis
* the length of time to sleep in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
/**
* 线程睡眠,这个比较常用,需要注意:
* 1.单位是毫秒
* 2.不会失去锁
* 3.yield 会放弃 CPU 资源吗,那 sleep 会放弃 CPU 资源吗? 出于好奇,做了一个小实验,如下:
*/
public static native void sleep(long millis) throws InterruptedException;
关于 sleep 是否会放弃CPU资源的小实验:
为了效果明显,对多个线程同时操作
① 创建多个线程,使它们同时执行 sleep 方法 ,查看程序的线程数以及CPU
第一次执行代码如下:
@Test
public void ThreadTest() throws InterruptedException {
for(int i = 0; i < 40; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("开启线程名称 :"+Thread.currentThread().getName());
try {
Thread.sleep(30*1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
thread.start();
}
System.out.println("主线程名称:"+Thread.currentThread().getName());
long start = System.currentTimeMillis();
long end = start;
long time = start - end;
while(time < 40*1000 ) {
end = System.currentTimeMillis();
time = end -start;
}
}
结果如下: sleep 后 CPU 使用情况并不高,程序中的线程确实是存在的
② 创建和第一次实验一样多的线程,只使其中一半线程 sleep ,另一半处于运行状态:
实验代码如下:
@Test
public void ThreadTest() throws InterruptedException {
for(int i = 0; i < 20; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("开启线程名称 :"+Thread.currentThread().getName());
try {
Thread.sleep(30*1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
thread.start();
}
for(int i = 0; i < 20; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("开启线程名称 :"+Thread.currentThread().getName());
try {
long start = System.currentTimeMillis();
long end = start;
long time = end - start;
while(time < 30*1000 ) {
end = System.currentTimeMillis();
time = end -start;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
thread.start();
}
System.out.println("主线程名称:"+Thread.currentThread().getName());
long start = System.currentTimeMillis();
long end = start;
long time = start - end;
while(time < 40*1000 ) {
end = System.currentTimeMillis();
time = end -start;
}
}
第二次实验结果如下: 可以看到 CPU 在一定区间内上升到 100%,
问题分析:
第一次 | 第二次 | |
---|---|---|
CPU使用情况 | 基本稳定在 12% | 运行程序后CPU迅速飙升 |
开启线程数量 | 40个线程全都调用sleep方法 | 40个线程(20个线程调用sleep方法,20个线程在30秒内空轮询占用 CPU资源) |
由实验对比可以得到结论,使用 sleep 的线程并不会去占用 CPU 资源 ,因为如果 sleep 占用 CPU 资源的话,第一次实验的CPU占用率不可能
实验完成,继续跟着源码,一点点的往下看:
/**
* Initializes a Thread. 初始化一个线程
*
* @param g the Thread group 线程组,线程组代表一组线程,此外线程组还可以包括其它线程组。线程组形成一个树,除了初始线程组外,每
* 个线程组都会有一个父进程
* @param target the object whose run() method gets called run方法被调用的目标对象
* @param name the name of the new Thread 新线程的名称
* @param stackSize the desired stack size for the new thread, or //栈大小
* zero to indicate that this parameter is to be ignored.
* @param acc the AccessControlContext to inherit, or //访问控制上下文对象
* AccessController.getContext() if null
* @param inheritThreadLocals if {@code true}, inherit initial values for
* inheritable thread-locals from the constructing thread
*/
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) { //如果线程组为空
/* Determine if it's an applet or not */ //确定它是否使一个小程序
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) { //如果 安全管理对象不为空
g = security.getThreadGroup(); //获取安全管理对象所在线程组对象,并赋给 g
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) { //如果g 为空,
g = parent.getThreadGroup(); //获取父线程对象所在的线程组对象,并赋给 g
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
//不管是否显示传递线程组,都应该使用 checkAccess
g.checkAccess();
/*
* Do we have the required permissions?
*/
//我们具有所需要的权限吗?
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;
setPriority(priority);
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
//Thread 不支持克隆,会抛出克隆不支持异常,这个了解一下就好了
/**
* Throws CloneNotSupportedException as a Thread can not be meaningfully
* cloned. Construct a new Thread instead.
*
* @throws CloneNotSupportedException
* always
*/
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
/**
* Allocates a new {@code Thread} object. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, null, gname)}, where {@code gname} is a newly generated
* name. Automatically generated names are of the form
* {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
*/
// Thread 构造方法,只需了解一下调用 init 方法传的参数就好
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
/**
* Allocates a new {@code Thread} object. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, target, gname)}, where {@code gname} is a newly generated
* name. Automatically generated names are of the form
* {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
*
* @param target
* the object whose {@code run} method is invoked when this thread
* is started. If {@code null}, this classes {@code run} method does
* nothing.
*/
// Thread 构造方法,只需了解一下调用 init 方法传的参数就好
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
... //一堆构造方法
/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the <code>run</code> method of this thread.
* <p>
* The result is that two threads are running concurrently: the
* current thread (which returns from the call to the
* <code>start</code> method) and the other thread (which executes its
* <code>run</code> method).
* <p>
* It is never legal to start a thread more than once.
* In particular, a thread may not be restarted once it has completed
* execution.
*
* @exception IllegalThreadStateException if the thread was already
* started.
* @see #run()
* @see #stop()
*/
/**
* 使该线程开始执行,Java 虚拟机调用这个线程的 run 方法
* 执行结果是两个线程正常运行:当前线程(指调用 start 方法的这个线程)和另一个线程(执行 run 方法的线程)
* 一个线程启动多次是不合法的,特别是执行完成后的线程,无法被重新启动(这个大家可以自己去验证下,就6行代码)
*/
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
//对于虚拟机创建/设置的main方法线程或"系统线程组",都不会调用此方法
//将来可能会向该方法添加新的内容
//0 状态值对应于状态“new”
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
//通知这个线程所在线程组,这个线程即将被启动,因此它能被添加到线程组列表中
//并且改组的未开始计数可以减少
group.add(this);
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 */
}
}
}
/**
* 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)
*/
//如果该线程是使用单独的 Runnable 运行对象构造的,则调用 Runnale 对象的 run 方法;否则,此方法不执行任何操作
//并返回。 Thread 的子类应该重写这个方法
@Override
public void run() {
if (target != null) {
target.run();
}
}
/**
* This method is called by the system to give a Thread
* a chance to clean up before it actually exits.
*/
//系统调用此方法,使线程有机会在线程退出之前进行清理
private void exit() {
if (group != null) {
group.threadTerminated(this); //通知线程组,这个线程已经终止了
group = null;
}
/* Aggressively null out all reference fields: see bug 4006245 */
//积极清空所有参考字段
target = null;
/* Speed the release of some of these resources */
//加快资源释放
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
/**
* Forces the thread to stop executing.
* <p>
* If there is a security manager installed, its <code>checkAccess</code>
* method is called with <code>this</code>
* as its argument. This may result in a
* <code>SecurityException</code> being raised (in the current thread).
* <p>
* If this thread is different from the current thread (that is, the current
* thread is trying to stop a thread other than itself), the
* security manager's <code>checkPermission</code> method (with a
* <code>RuntimePermission("stopThread")</code> argument) is called in
* addition.
* Again, this may result in throwing a
* <code>SecurityException</code> (in the current thread).
* <p>
* The thread represented by this thread is forced to stop whatever
* it is doing abnormally and to throw a newly created
* <code>ThreadDeath</code> object as an exception.
* <p>
* It is permitted to stop a thread that has not yet been started.
* If the thread is eventually started, it immediately terminates.
* <p>
* An application should not normally try to catch
* <code>ThreadDeath</code> unless it must do some extraordinary
* cleanup operation (note that the throwing of
* <code>ThreadDeath</code> causes <code>finally</code> clauses of
* <code>try</code> statements to be executed before the thread
* officially dies). If a <code>catch</code> clause catches a
* <code>ThreadDeath</code> object, it is important to rethrow the
* object so that the thread actually dies.
* <p>
* The top-level error handler that reacts to otherwise uncaught
* exceptions does not print out a message or otherwise notify the
* application if the uncaught exception is an instance of
* <code>ThreadDeath</code>.
*
* @exception SecurityException if the current thread cannot
* modify this thread.
* @see #interrupt()
* @see #checkAccess()
* @see #run()
* @see #start()
* @see ThreadDeath
* @see ThreadGroup#uncaughtException(Thread,Throwable)
* @see SecurityManager#checkAccess(Thread)
* @see SecurityManager#checkPermission
* @deprecated This method is inherently unsafe. Stopping a thread with
* Thread.stop causes it to unlock all of the monitors that it
* has locked (as a natural consequence of the unchecked
* <code>ThreadDeath</code> exception propagating up the stack). If
* any of the objects previously protected by these monitors were in
* an inconsistent state, the damaged objects become visible to
* other threads, potentially resulting in arbitrary behavior. Many
* uses of <code>stop</code> should be replaced by code that simply
* modifies some variable to indicate that the target thread should
* stop running. The target thread should check this variable
* regularly, and return from its run method in an orderly fashion
* if the variable indicates that it is to stop running. If the
* target thread waits for long periods (on a condition variable,
* for example), the <code>interrupt</code> method should be used to
* interrupt the wait.
* For more information, see
* <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
* are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
*/
/**
* 强制线程停止执行(不推荐)
* 如果安装了安全管理器,它的checkAccess 方法this作为参数。这可能导致 SecurityException 被提升(在当前线程中)
* 如果此线程与当前线程不同(即当前线程试图停止除本身线程之外的线程) ,则另外还调用安全管理里器的 checkPermission
* 方法。在这种情况下,这可能会抛出 SecurityException 异常(在当前线程中)
* 由该线程表示的线程被强制停止,它正在异常进行,并抛出一个新键的 ThreadDeath 对象作为例外
* 允许停止尚未启动的线程。如果线程最终启动,它将立即终止
* 一个应用程序通常不应该尝试捕获 ThreadDeath ,除非它必须做一些非凡的清除工作(注意:抛出ThreadDeath对象导致
* finally 语句try语句在线程正式死亡前执行 )。如果一个 catch 子句捕获一个 ThreadDeath 对象,重要的是重新抛出
* 该对象,使线程实际上死亡
* 捕获的异常不打印出消息,或者未捕获的异常是一个实例,否则通知应用程序的顶级错误处理程序 ThreadDeath
*/
//这个方法本质上是不安全的。使用Thread.stop 停止线程可以解锁所有已锁定的监视器(由ThreadDeath异常在堆栈中的
//自然结果)。如果先前受这些监视器保护的任何对象处于不一致的状态,则损坏的对象变得对其他线程可见,可能会导致任意
//行为
@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.
//状态值 0 对应于 “NEW” ,因为我们持有锁,不能更改为 NOT-NEW
if (threadStatus != 0) {
resume(); // Wake up thread if it was suspended; no-op otherwise
}
// The VM can handle all thread states
//
stop0(new ThreadDeath());
}
/**
* Interrupts this thread.
*
* <p> Unless the current thread is interrupting itself, which is
* always permitted, the {@link #checkAccess() checkAccess} method
* of this thread is invoked, which may cause a {@link
* SecurityException} to be thrown.
*
* <p> If this thread is blocked in an invocation of the {@link
* Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
* Object#wait(long, int) wait(long, int)} methods of the {@link Object}
* class, or of the {@link #join()}, {@link #join(long)}, {@link
* #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
* methods of this class, then its interrupt status will be cleared and it
* will receive an {@link InterruptedException}.
*
* <p> If this thread is blocked in an I/O operation upon an {@link
* java.nio.channels.InterruptibleChannel InterruptibleChannel}
* then the channel will be closed, the thread's interrupt
* status will be set, and the thread will receive a {@link
* java.nio.channels.ClosedByInterruptException}.
*
* <p> If this thread is blocked in a {@link java.nio.channels.Selector}
* then the thread's interrupt status will be set and it will return
* immediately from the selection operation, possibly with a non-zero
* value, just as if the selector's {@link
* java.nio.channels.Selector#wakeup wakeup} method were invoked.
*
* <p> If none of the previous conditions hold then this thread's interrupt
* status will be set. </p>
*
* <p> Interrupting a thread that is not alive need not have any effect.
*
* @throws SecurityException
* if the current thread cannot modify this thread
*
* @revised 6.0
* @spec JSR-51
*/
/**
* 中断这个线程
* 除非始终允许当前线程中断自身,否则将调用次线程的checkAccess方法,这可能会引发 SecurityException
* 如果该线程阻塞的调用wait(),wait(long),或 wait(long,int)的方法 或者
* join(),join(long),join(long,int),sleep(long),或 sleep(long,int)方法,那么它的中断状态将被清
* 除,并且将收到一个 InterruptedException
* 如果该线程在 InterruptibleChannel 上的I/O操作被终止 则通道将被关闭,该线程的中断状态将被设置,并将收
* 到 ClosedInterruptException
* 如果该线程在 Selector 中被阻塞,则线程的中断状态将被设置,并且它将从选择操作立即返回,可能具有非零值,就像调
* 用了选择器 wakeup 方法一样。
* 如果以前的条件都不成立,则该线程的中断状态将被设置
* 中断不存在的线程不需要任何效果
*
*/
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();
}
/**
* Tests whether the current thread has been interrupted. The
* <i>interrupted status</i> of the thread is cleared by this method. In
* other words, if this method were to be called twice in succession, the
* second call would return false (unless the current thread were
* interrupted again, after the first call had cleared its interrupted
* status and before the second call had examined it).
*
* <p>A thread interruption ignored because a thread was not alive
* at the time of the interrupt will be reflected by this method
* returning false.
*
* @return <code>true</code> if the current thread has been interrupted;
* <code>false</code> otherwise.
* @see #isInterrupted()
* @revised 6.0
*/
/**
* 测是当前线程是否中断。线程的中断状态被这个方法清除。换句话说,如果这个方法被成功调用两次,第二次调用将返回
* false (除非当前线程再一次被中断,在第一次调用后已经被清除它的中断标记,并且在第二次调用前已经检查过)
*/
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
/**
* Tests whether this thread has been interrupted. The <i>interrupted
* status</i> of the thread is unaffected by this method.
*
* <p>A thread interruption ignored because a thread was not alive
* at the time of the interrupt will be reflected by this method
* returning false.
*
* @return <code>true</code> if this thread has been interrupted;
* <code>false</code> otherwise.
* @see #interrupted()
* @revised 6.0
*/
/**
* 测试这个线程是否已经被中断,线程的中断状态不受此方法的影响
*/
public boolean isInterrupted() {
return isInterrupted(false);
}
/**
* Tests if some Thread has been interrupted. The interrupted state
* is reset or not based on the value of ClearInterrupted that is
* passed.
* 根据传递的 ClearInterrupted 的值,是否重置中断状态
*/
private native boolean isInterrupted(boolean ClearInterrupted);
这一块有丢丢小坑:
在上面的源码中,可以看到以下这两个方法:
//注意这个没有用static修饰的是中断开启的 thread 对象
public void interrupt()
// 注意这个有 static 修饰的方法,中断的是调用该线程的线程(我们知道,是存在两个线程的,比如我们在main中开启一个线程执行我们想要
// 的程序,这里存在两个线程,第一个就是我们的主线程,另一个是我们开启的线程 ),这个方法中断的是 调用执行这个方法的线程,也就是
// 说:interrupted() 作用于当前线程
public static boolean interrupted()
我不知道有没说清楚,如图:
//这两个稍微看一下吧,平时感觉也没用到过,返回的数据是一个 StackTraceElement 数组,每一个都代表着一个栈帧(不知道的可以百度或《java虚拟机
//规范》中有提到,记得不是很清楚了),效果如下:
public StackTraceElement[] getStackTrace()
public static Map<Thread, StackTraceElement[]> getAllStackTraces()
代码:
@Test
public void test3() {
Thread thread = new Thread(()->{
System.out.println("启动线程名:"+Thread.currentThread().getName());
while(true) {
Thread.currentThread().getName();
}
});
thread.start();
System.out.println("--------------------------------");
StackTraceElement[] vals = thread.getStackTrace();
System.out.println("thread "+thread.getName()+" : ");
for(StackTraceElement val:vals) {
System.out.println(" ==> "+val);
}
System.out.println("--------------------------------");
Map<Thread,StackTraceElement[]> map = Thread.getAllStackTraces();
Set<Thread> threads = map.keySet();
for(Thread key:threads) {
StackTraceElement[] values = map.get(key);
System.out.println("key:"+key.getName()+ ": ");
for(StackTraceElement value:values) {
System.out.println(" "+value);
}
}
}
效果:
可以看到运行两次,得到的栈帧是不同的(当然可能也是相同的),所以利用这个方法对问题进行排查时,要注意要使数据加载进栈帧中才能得到完整的数据,不然得到的数据可能不完整,给问题排查造成困难
/** cache of subclass security audit results */
/* Replace with ConcurrentReferenceHashMap when/if it appears in a future
* release */
// 子类安全审核结果的缓存
// 当/如果它在将来的版本中出现,请用 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 */
// 已审计子类弱引用队列
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();
}
/**
* 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.
*/
// 验证是否可以在不违反安全约束的情况下构造此(可能是子类)实例:子类不得覆盖对安全性敏感的非最终方法,否则将检查
// “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();
}
/**
* 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.
*/
//使用反射的方式去检查验证子类它没有重写安全敏感非最终方法,如果重写了将返回 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; // 参数类不是 Thread 类
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();
}
public enum State { // 线程的状态
/**
* Thread state for a thread which has not yet started.
*/
//线程还未启动时的状态
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
// 一个可运行的状态,在java虚拟机中,一个线程在可运行状态是正在执行的,但它可能正在等待操作系统的其它资源,
// 例如:处理器资源
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
// 线程的阻塞状态是等待一个监视器锁
// 一个阻塞状态的线程是正在等待监视器锁去进入一个同步块/方法,或者 在调用Object的wait方法后,重新进入一个同步块/方法
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
// 一个等待线程伴随一个特定的等待时间
// 一个线程在定时等待状态由于调用了以下指定的方法
// Thread.sleep Object.wait(long)(注意:这里这个有参数) Thread.join(long)
// LockSupport.parkNanos LockSupport.parkUnitil
//
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
// 线程终止状态
// 线程已经完成执行
TERMINATED;
}
/**
* 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
*/
/**
* 这个方法比较重要
* 当一个 uncaught exception 导致线程突然终止时,调用这个接口的处理方法
* 当由于未捕获异常导致一个线程即将终止时,Java虚拟机将会通过getUncaughtExceptionHandler方法查询这个线程的未捕获异常处理器
* (UncaughtExceptionHandler),并且将会调用这个处理器的 uncaughtException 方法,将线程和异常作为参数传递
* 如果没有显示设置线程的 UncaughtExceptionHandler,则其 ThreadGroup 对象将用作其 UncaughtExceptionHandler。
* 如果线程组(ThreadGroup)对象也没有指定要求去处理这个异常, 它将调用转发到默认的未捕获异常处理程序
* (getDefaultUncaughtExceptionHandler) 中
*/
@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
*/
/**
* 由于的未捕获异常(uncaught exception)导致线程终止时,方法被调用
* Java 虚拟机将忽略此方法引发的任何异常(也就是说,这个方法产生的异常不能在往外抛了,抛了虚拟机也会忽略不进行处理)
* 它的set和get 方法就没必要说了,但要注意默认的前面有 static 修饰
*/
void uncaughtException(Thread t, Throwable e);
}
// 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.
// 以下三个最初未初始化的字段仅由类 java.util.concurrent.ThreadLocalRandom 管理
// 这些字段用于在并发代码中购机按搞性能 PRNG,因此我们不会冒意外的错误共享的风险
// 因此,使用 @Contended. 隔离字段
// 意外发现新大陆了!!!结尾有惊喜
/** The current seed for a ThreadLocalRandom */
// ThreadLocalRandom的当前种子
@sun.misc.Contended("tlr")
long threadLocalRandomSeed;
/** Probe hash value; nonzero if threadLocalRandomSeed initialized */
// 探针哈希值;如果 threadLocalRandomSeed 初始化,则为非零
@sun.misc.Contended("tlr")
int threadLocalRandomProbe;
/** Secondary seed isolated from public ThreadLocalRandom sequence */
// 从公共 ThreadLocalRandom 序列中分离的次要种子 这些是什么我暂时也不知道,先放这里一段时间吧!!!
@sun.misc.Contended("tlr")
int threadLocalRandomSecondarySeed;