23.jdk源码阅读之Thread(下)
1. 写在前面
上篇文章我们介绍了Tread的一些方法的底层代码实现,这篇文章我们继续。
2. join()方法的底层实现
/*** Waits at most {@code millis} milliseconds for this thread to* die. A timeout of {@code 0} means to wait forever.** <p> This implementation uses a loop of {@code this.wait} calls* conditioned on {@code this.isAlive}. As a thread terminates the* {@code this.notifyAll} method is invoked. It is recommended that* applications not use {@code wait}, {@code notify}, or* {@code notifyAll} on {@code Thread} instances.** @param millis* the time to wait 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 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;}}}/*** Waits at most {@code millis} milliseconds plus* {@code nanos} nanoseconds for this thread to die.** <p> This implementation uses a loop of {@code this.wait} calls* conditioned on {@code this.isAlive}. As a thread terminates the* {@code this.notifyAll} method is invoked. It is recommended that* applications not use {@code wait}, {@code notify}, or* {@code notifyAll} on {@code Thread} instances.** @param millis* the time to wait in milliseconds** @param nanos* {@code 0-999999} additional nanoseconds to wait** @throws IllegalArgumentException* if the value of {@code millis} is negative, or the value* of {@code nanos} is not in the range {@code 0-999999}** @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 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);}/*** Waits for this thread to die.** <p> An invocation of this method behaves in exactly the same* way as the invocation** <blockquote>* {@linkplain #join(long) join}{@code (0)}* </blockquote>** @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 final void join() throws InterruptedException {join(0);}
这段代码展示了 Java Thread 类中的 join() 方法的几种重载实现。join() 方法的主要功能是让当前线程等待另一个线程的终止。通过调用 join(),当前线程会被阻塞,直到目标线程完成执行。
2.1 join(long millis)
2.1.1 参数
- millis:等待的时间,以毫秒为单位。值为0表示无限等待。
2.1.2 异常
- IllegalArgumentException:如果 millis 为负数。
- InterruptedException:如果当前线程在等待过程中被中断。
2.1.3 实现
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;}}
}
- 记录当前时间。
- 检查 millis 是否为负数,如果是,则抛出 IllegalArgumentException。
- 如果 millis 为 0,当前线程会无限期等待,直到目标线程终止。
- 否则,当前线程会等待指定的毫秒数,使用 wait() 方法进行等待,并定期检查目标线程是否仍然存活。
2.2 join(long millis, int nanos)
2.2.1 参数
- millis:等待的时间,以毫秒为单位。
- nanos:额外等待的时间,以纳秒为单位,范围是 0 到 999999。
2.2.2 异常
- IllegalArgumentException:如果 millis 为负数,或 nanos 不在 0 到 999999 之间。
- InterruptedException:如果当前线程在等待过程中被中断。
2.2.3 实现
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);
}
- 检查 millis 和 nanos 的有效性
- 如果 nanos 大于等于 500000 或者 nanos 不为 0 且 millis 为 0,则将 millis 增加 1。
- 调用 join(millis) 方法进行等待。
2.3 join()
调用 join(0) 方法,即无限期等待目标线程终止。
3. interrupt()方法的底层实现
public void interrupt() {if (this != Thread.currentThread())checkAccess();synchronized (blockerLock) {Interruptible b = blocker;if (b != null) {interrupt0(); // Just to set the interrupt flagb.interrupt(this);return;}}interrupt0();}
interrupt() 方法用于中断线程的执行。中断线程的主要目的是通知线程它应该停止当前的工作,并尽快终止。
3.1 中断线程
如果当前线程不是在中断自己(即 this != Thread.currentThread()),则调用 checkAccess() 方法检查权限,可能会抛出 SecurityException。
3.2 线程阻塞的情况
- 如果线程在调用 Object 类的 wait()、wait(long)、wait(long, int) 方法,或者 Thread 类的 join()、join(long)、join(long, int)、sleep(long)、sleep(long, int) 方法时被阻塞,中断会清除线程的中断状态并抛出 InterruptedException。
- 如果线程在 I/O 操作中被阻塞(例如在 InterruptibleChannel 上),中断会关闭通道,设置线程的中断状态,并抛出 ClosedByInterruptException。
- 如果线程在 Selector 上被阻塞,中断会设置线程的中断状态,并立即从选择操作返回,可能返回一个非零值,就像调用了 Selector 的 wakeup 方法一样。
- 如果以上情况都不适用,则仅设置线程的中断状态。
3.3 中断非活动线程
中断一个不活跃的线程可能没有任何效果。
3.4 同步块
synchronized (blockerLock) {Interruptible b = blocker;if (b != null) {interrupt0(); // Just to set the interrupt flagb.interrupt(this);return;}}
- 使用 blockerLock 对象进行同步,以确保在检查和修改 blocker 时的线程安全。
- Interruptible b = blocker;:获取当前线程的 blocker 对象。
- 如果 blocker 不为 null,调用 interrupt0() 方法设置中断标志,然后调用 blocker 的 interrupt(this) 方法进行中断处理,并返回。
3.5 设置中断标志
如果 blocker 为 null,直接调用 interrupt0() 方法设置中断标志。
3.6 interrupt0()
本地方法,用于设置线程的中断状态。
4. setPriority(int newPriority)
setPriority 方法用于设置线程的优先级。线程的优先级是一个整数值,通常用于调度线程的执行顺序,但具体的调度行为依赖于底层操作系统和 JVM 实现。
4.1 声明变量
ThreadGroup g;
4.2 检查访问权限
checkAccess();
调用 checkAccess() 方法,确保当前线程有权限修改目标线程。如果没有权限,可能会抛出 SecurityException。
4.3 验证优先级范围
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {throw new IllegalArgumentException();
}
检查 newPriority 是否在合法范围内(即不大于 MAX_PRIORITY 且不小于 MIN_PRIORITY)。如果不在范围内,则抛出 IllegalArgumentException。
4.4 获取线程组
if((g = getThreadGroup()) != null) {
获取当前线程所属的线程组 ThreadGroup。如果线程组不为 null,则继续执行。
4.5 调整优先级
if (newPriority > g.getMaxPriority()) {newPriority = g.getMaxPriority();
}
如果 newPriority 大于线程组的最大优先级 g.getMaxPriority(),则将 newPriority 调整为线程组的最大优先级。
4.6 设置优先级
setPriority0(priority = newPriority);
调用本地方法 setPriority0(int newPriority) 设置线程的优先级,并将 priority 字段更新为 newPriority。
系列文章
1.JDK源码阅读之环境搭建
2.JDK源码阅读之目录介绍
3.jdk源码阅读之ArrayList(上)
4.jdk源码阅读之ArrayList(下)
5.jdk源码阅读之HashMap
6.jdk源码阅读之HashMap(下)
7.jdk源码阅读之ConcurrentHashMap(上)
8.jdk源码阅读之ConcurrentHashMap(下)
9.jdk源码阅读之ThreadLocal
10.jdk源码阅读之ReentrantLock
11.jdk源码阅读之CountDownLatch
12.jdk源码阅读之CyclicBarrier
13.jdk源码阅读之Semaphore
14.jdk源码阅读之线程池(上)
15.jdk源码阅读之线程池(下)
16.jdk源码阅读之ArrayBlockingQueue
17.jdk源码阅读之LinkedBlockingQueue
18.jdk源码阅读之CopyOnWriteArrayList
19.jdk源码阅读之FutureTask
20.jdk源码阅读之CompletableFuture
21.jdk源码阅读之AtomicLong
22.jdk源码阅读之Thread(上)