From 238fdcdb74526201ea55e030493c398adba51146 Mon Sep 17 00:00:00 2001 From: AmyliaY <471816751@qq.com> Date: Wed, 8 Apr 2020 23:10:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=20Thread=E7=B1=BB=20?= =?UTF-8?q?=E6=BA=90=E7=A0=81=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/JDK/Thread.md | 66 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/docs/JDK/Thread.md b/docs/JDK/Thread.md index a9aa687..b29ae98 100644 --- a/docs/JDK/Thread.md +++ b/docs/JDK/Thread.md @@ -10,21 +10,28 @@ public class Thread implements Runnable { private int priority; /** 是否为守护线程 */ private boolean daemon; - /** 目标任务 */ + /** 线程要执行的目标任务 */ private Runnable target; /** 所属线程组 */ private ThreadGroup group; /** 类加载器 */ private ClassLoader contextClassLoader; /** - * ThreadLocal设置线程私有变量时 就是通过下面这两个参数完成的, - * ThreadLocal的get/set方法就是通过操作 各个线程的 threadLocals 变量实现的 + * ThreadLocal 能为线程设置线程私有变量 就是通过下面这个threadLocals变量完成的, + * ThreadLocal的get/set方法就是通过操作 各个线程的 threadLocals 变量实现的。 + * 1、线程A持有一个 ThreadLocalMap 变量; + * 2、线程A调用一个类的 ThreadLocal变量 tlA 的 get/set方法; + * 3、tlA(ThreadLocal)的 get/set方法 获取当前线程A,调用 线程A 的 ThreadLocalMap变量 的get/put方法; + * 4、其它线程 调用 tlA(ThreadLocal)的 get/set方法 同理。 */ ThreadLocal.ThreadLocalMap threadLocals; ThreadLocal.ThreadLocalMap inheritableThreadLocals; /** 线程栈的大小 */ private long stackSize; - /** 线程状态:新建、就绪/运行、阻塞、等待、销毁 */ + /** + * Thread类定义了6个线程状态:New、Runnable、Blocked、Waiting、TimedWaiting、Terminated(终止) + * 实际上还会把 Runnable 再细分为 就绪(未抢到时间片) 和 运行中(抢到时间片) + */ private volatile int threadStatus; /** 最小优先级 */ public static final int MIN_PRIORITY = 1; @@ -39,7 +46,7 @@ public class Thread implements Runnable { * RUNNABLE: 运行,在java多线程模型中,就绪和运行都是运行状态; * BLOCKED: 阻塞; * WAITING: 等待,需要其他的线程来唤醒; - * TIMED_WAITING:超时等待,可以在指定的时间内自动醒来; + * TIMED_WAITING:超时等待,可以在指定的时间内自动醒来,如 sleep()方法; * TERMINATED: 终止,线程执行完毕。 */ public static final class State extends Enum { @@ -69,8 +76,8 @@ public class Thread implements Runnable { /** * 一系列 构造方法 ------------------------------------------------------ - * 可以看出来,其中都调用了init()方法,这也是一个约定俗成的规矩, 即,如果要在 new 时进行一些初始化操作,那么请将初始化操作单独写在 - * init()方法中,然后在构造函数中调用该 init()方法 + * 可以看出来,其中都调用了init()方法,这也是一个约定俗成的规矩, 即,如果要在 new 时进行一些初始化操作, + * 那么请将初始化操作单独写在 init()方法中,然后在构造函数中调用该 init()方法 */ public Thread() { daemon = false; @@ -261,6 +268,51 @@ public class Thread implements Runnable { } private native void interrupt0(); + + /** + * 线程main 调用了线程A的join方法,则 线程main 会被阻塞,直到线程A执行完毕 + */ + public final void join() throws InterruptedException { + join(0); + } + + /** + * 实际上是利用 wait/notify机制 来实现的 + */ + 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"); + } + // millis 为 0,所以走这个分支 + if (millis == 0) { + // 当前线程是否还在运行,还在运行 则main线程 进入等待状态,直到 A线程运行完毕,将其唤醒 + while (isAlive()) { + wait(0); + } + } else { + while (isAlive()) { + long delay = millis - now; + if (delay <= 0) { + break; + } + wait(delay); + now = System.currentTimeMillis() - base; + } + } + } + + /** + * 线程睡眠指定的时间,释放CPU资源,但不释放锁 + */ + public static native void sleep(long millis) throws InterruptedException; + + /** + * 线程是否还在运行 + */ + public final native boolean isAlive(); } ``` 之前一直对线程状态 及 状态切换的概念模糊不清,现在通过源码中对线程状态的定义,我们可以画张图来重新回顾一下,以使我们对其有更加深刻的理解。