共计 6827 个字符,预计需要花费 18 分钟才能阅读完成。
零 前期准备
0 FBI WARNING
文章异常啰嗦且绕弯。
1 版本
JDK 版本 : OpenJDK 12.0.1
IDE : idea 2019.2
2 Thread 简介
Thread 对象是 java 中线程的封装对象,用于控制线程的一切属性,也是 java 中最常用到的基础对象之一。
一 正文
1 Thread 类和成员变量
1.1 Thread 和 Runnable
在工程实践中 Thread 经常与 Runnable 一同使用,用于运行多线程程序。而本质上 Thread 也实现了 Runnnable:
// Thread.class
public class Thread implements Runnable {
// 忽略其它成员变量和方法,暂时先只关注 Runnable 相关的方法
// ...
// 在创建 Thread 对象的时候可以传入的 Runnable 对象
// 如果不传入则 run() 方法无效
private Runnable target;
// 执行 target 对象
// 由此可见 Thread 本身其实是一个静态代理的典例
@Override
public void run() {if (target != null) {target.run();
}
}
}
1.2 成员变量
// 线程名称
private volatile String name;
// 线程优先级,数字越大优先级越高
private int priority;
// 最小优先级
public static final int MIN_PRIORITY = 1;
// 默认优先级
public static final int NORM_PRIORITY = 5;
// 最高优先级
public static final int MAX_PRIORITY = 10;
// 是否是守护线程,默认为 否
private boolean daemon = false;
/* Fields reserved for exclusive use by the JVM */
private boolean stillborn = false;
private long eetop;
// Runnable
private Runnable target;
// 该线程对象属于哪个线程组
private ThreadGroup group;
// 类加载器
private ClassLoader contextClassLoader;
private AccessControlContext inheritedAccessControlContext;
private static int threadInitNumber;
// 线程绑定的 ThreadLocal
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
// 栈大小
private final long stackSize;
private long nativeParkEventPointer;
// 线程 id
private final long tid;
private static long threadSeqNumber;
// 线程状态
private volatile int threadStatus;
// 用来作为锁的对象
volatile Object parkBlocker;
// 用来作为锁的对象
private final Object blockerLock = new Object();
private volatile Interruptible blocker;
2 构造器
Thread 有许多重载的构造器,但是基本上都只是在值数量上做了封装,核心的构造器逻辑只有一个:
// Thread.class
private Thread(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;
// currentThread() 方法会获取到当前线程的线程对象
// 由于当前线程是创建该线程的线程,所以是该线程对象的 父线程
Thread parent = currentThread();
// 权限控制器
SecurityManager security = System.getSecurityManager();
if (g == null) {if (security != null) {g = security.getThreadGroup();
}
if (g == null) {
// 如果没有组的话,会获取到 父线程 的线程组赋值给子线程
g = parent.getThreadGroup();}
}
g.checkAccess();
// 权限控制器
if (security != null) {if (isCCLOverridden(getClass())) {
security.checkPermission(SecurityConstants.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);
// threadLocal 配置
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
// 栈深度
this.stackSize = stackSize;
// 生成一个唯一的线程 id
this.tid = nextThreadID();}
3 start
start() 方法是 Thread 对象启动新线程的核心方法:
// Thread.class
// step 1
public synchronized void start() {
// 先判断线程的状态,如果线程状态不正确直接抛出错误
if (threadStatus != 0)
throw new IllegalThreadStateException();
// 将对象添加到线程组
group.add(this);
// 线程是否正常启动的标识对象
boolean started = false;
try {
// 调用 native 的线程启动方法
start0();
// 修改标识对象
started = true;
} finally {
try {
// 如果 started 仍然等于 false
// 那么此处会在线程组中添加失败信息
if (!started) {group.threadStartFailed(this);
}
} catch (Throwable ignore) {// 此处没有做任何异常处理}
}
}
// step 2
// native 方法启动线程
private native void start0();
4 sleep
sleep(…) 方法是用来休眠线程的常用方法:
// Thread.class
// step 1
public static void sleep(long millis, int nanos) throws InterruptedException {
// 此方法中使用者可以输入 毫秒 和 纳秒 两个参数
// 但是实际上 java 只支持到毫秒级的线程休眠
// 如果纳秒数大于零,那么就会在毫秒数上 +1,意思是多休眠一毫秒
// 这个方法预留出来不太清楚具体作用
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 > 0 && millis < Long.MAX_VALUE) {millis++;}
// 调用 native 的休眠方法
sleep(millis);
}
// step 2
// native 方法休眠线程
public static native void sleep(long millis) throws InterruptedException;
5 interrupt
interrupt() 方法是用来中断线程的常用方法:
// Thread.class
// step 1
public void interrupt() {
// 如果当前方法的调用线程不是此线程对象代表的线程,则进入该段逻辑
// 此处会优先使用 Interruptible(中断器) 去中断当前线程
// 如果没有配置中断器,那么调用自身的 native 方法去中断线程
if (this != Thread.currentThread()) {// checkAccess() 方法用于确认权限控制器
checkAccess();
synchronized (blockerLock) {
// 此处可以自定义中断器
Interruptible b = blocker;
if (b != null) {b.interrupt(this);
return;
}
}
}
// 调用 native 的线程中断方法
interrupt0();}
// step 2
private native void interrupt0();
另外关于线程的中断,还有一些方法:
// 判断当前线程的线程状态
public static boolean interrupted() {// currentThread() 方法会获取到当前线程的线程对象
// 然后判断此线程对象是否被中断了
// 如果是被中断的,那么此处恢复线程
return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
// 不会恢复线程的中断状态
return isInterrupted(false);
}
@HotSpotIntrinsicCandidate
private native boolean isInterrupted(boolean ClearInterrupted);
5 join
join() 方法是用阻塞调用线程,等待对象线程结束之后再执行之后操作的方法:
// Thread.class
// step 1
public final void join() throws InterruptedException {join(0);
}
// step 2
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");
}
// 在这里判断 nanos 的值,如果在合理范围内,就在 millis 上加一
// 这里可知,其实 join(...) 方法并不支持纳秒级别的时间间隔
if (nanos > 0 && millis < Long.MAX_VALUE) {millis++;}
// 调用 step 3 中的 join(...) 方法
join(millis);
}
// step 3
// 核心的 join(...) 方法,具体的阻塞逻辑
public final synchronized void join(final long millis) throws InterruptedException {
// 如果设置了超时时间,那么超过时间了就会停止阻塞
if (millis > 0) {if (isAlive()) {final long startTime = System.nanoTime();
long delay = millis;
do {wait(delay);
} while (isAlive()
&& (delay = millis - TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)) > 0);
}
} else if (millis == 0) {
// 不设置超时时间,此处一直等待直到执行完毕
while (isAlive()) {wait(0);
}
} else {throw new IllegalArgumentException("timeout value is negative");
}
}
由上述源码可知,join(…) 方法的本质是阻塞当前线程,一直到目标的线程对象不再存活 (isAlive() == false) 为止。
6 主要的 native 方法
实际上 Thread 是一个非常底层的类,大多数的方法都是 native 修饰的,即底层调用了 c 语言写的代码。
// 获取当前线程的线程对象
public static native Thread currentThread();
// 让出线程的时间片,即为短暂暂停线程的活动让给其它线程使用
public static native void yield();
7 其它方法
Thread 中还有一些特殊的和预留的方法:
// jdk9 中新加的空方法,暂不清楚用途
@HotSpotIntrinsicCandidate
public static void onSpinWait() {}
// 复写了 Object 的 clone() 方法,但是只要被调用就会报错
// 说明 Thread 对象不可被复制
@Override
protected Object clone() throws CloneNotSupportedException {throw new CloneNotSupportedException();
}
// 退出线程,逻辑很简单,即为置空成员变量,帮助 gc
private void exit() {if (threadLocals != null && TerminatingThreadLocal.REGISTRY.isPresent()) {TerminatingThreadLocal.threadTerminated();
}
if (group != null) {group.threadTerminated(this);
group = null;
}
target = null;
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
// 判断线程组内活跃的线程数量
public static int activeCount() {return currentThread().getThreadGroup().activeCount();
}
// 设置为守护线程
public final void setDaemon(boolean on) {
// 此处设置权限
checkAccess();
// 如果此线程此时还处于存活状态,那么就会报错
// 即为,只有线程未启动的时候才能进行守护线程的设置
if (isAlive()) {throw new IllegalThreadStateException();
}
daemon = on;
}
8 线程状态
java 中的线程的状态,以枚举对象的形式存在:
public enum State {
NEW, // 新建状态,尚未启动
RUNNABLE, // 可运行状态,即为运行状态
BLOCKED, // 阻塞状态
WAITING, // 等待状态
TIMED_WAITING, // 限时等待状态
TERMINATED; // 终止状态
}
本文仅为个人的学习笔记,可能存在错误或者表述不清的地方,有缘补充
正文完
发表至: java
2019-10-25