diff --git a/README.md b/README.md index 54f7bda..d1699ea 100644 --- a/README.md +++ b/README.md @@ -145,11 +145,13 @@ - 努力编写中... ## 番外篇(JDK 1.8) -- [Executor 线程池组件](docs/JDK/Executor线程池组件.md) -- [Lock 锁组件](docs/JDK/Lock锁组件.md) -- [HashMap 源码赏析](docs/JDK/HashMap.md) -- [ConcurrentHashMap 源码赏析](docs/JDK/ConcurrentHashMap.md) -- [String 源码赏析](docs/JDK/String.md) +- [Executor 线程池组件 源码赏析](docs/JDK/Executor线程池组件.md) +- [Lock 锁组件 源码赏析](docs/JDK/Lock锁组件.md) +- [Thread类 源码赏析](docs/JDK/Thread.md) +- [ThreadLocal组件 源码赏析](docs/JDK/ThreadLocal.md) +- [HashMap类 源码赏析](docs/JDK/HashMap.md) +- [ConcurrentHashMap类 源码赏析](docs/JDK/ConcurrentHashMap.md) +- [String类 源码赏析](docs/JDK/String.md) ## 学习心得 ### 个人经验 diff --git a/docs/JDK/Thread.md b/docs/JDK/Thread.md new file mode 100644 index 0000000..a9aa687 --- /dev/null +++ b/docs/JDK/Thread.md @@ -0,0 +1,268 @@ +本来想看 ThreadLocal 的源码的,但发现其中最重要的 get/set 方法都是操纵的 Thread类 中的 threadLocals变量 (java.lang.ThreadLocal.ThreadLocalMap),索性先来看一下 Thread 的源码吧,可以留意一下其中与 ThreadLocal 相关的属性,这样下次阅读 ThreadLocal 的核心API时,就能够轻易理解其原理咯。不多BB,直接上硬菜。 + +实现多线程从本质上都是由 Thread类 来完成的,其源码量很多,本次只看一些常见且重要的部分,源码和解析如下。 +```java +public class Thread implements Runnable { + /** 这里只看一些 常见的参数 */ + /** 线程名 */ + private volatile char name[]; + /** 优先级 */ + private int priority; + /** 是否为守护线程 */ + private boolean daemon; + /** 目标任务 */ + private Runnable target; + /** 所属线程组 */ + private ThreadGroup group; + /** 类加载器 */ + private ClassLoader contextClassLoader; + /** + * ThreadLocal设置线程私有变量时 就是通过下面这两个参数完成的, + * ThreadLocal的get/set方法就是通过操作 各个线程的 threadLocals 变量实现的 + */ + ThreadLocal.ThreadLocalMap threadLocals; + ThreadLocal.ThreadLocalMap inheritableThreadLocals; + /** 线程栈的大小 */ + private long stackSize; + /** 线程状态:新建、就绪/运行、阻塞、等待、销毁 */ + private volatile int threadStatus; + /** 最小优先级 */ + public static final int MIN_PRIORITY = 1; + /** 中等优先级 */ + public static final int NORM_PRIORITY = 5; + /** 最大优先级 */ + public static final int MAX_PRIORITY = 10; + + /** + * 内部枚举类,用来描述线程状态,状态值有: + * NEW: 新建,还未调用start()方法; + * RUNNABLE: 运行,在java多线程模型中,就绪和运行都是运行状态; + * BLOCKED: 阻塞; + * WAITING: 等待,需要其他的线程来唤醒; + * TIMED_WAITING:超时等待,可以在指定的时间内自动醒来; + * TERMINATED: 终止,线程执行完毕。 + */ + public static final class State extends Enum { + + public static final State NEW; + public static final State RUNNABLE; + public static final State BLOCKED; + public static final State WAITING; + public static final State TIMED_WAITING; + public static final State TERMINATED; + private static final State VALUES[]; + + static { + NEW = new State("NEW", 0); + RUNNABLE = new State("RUNNABLE", 1); + BLOCKED = new State("BLOCKED", 2); + WAITING = new State("WAITING", 3); + TIMED_WAITING = new State("TIMED_WAITING", 4); + TERMINATED = new State("TERMINATED", 5); + VALUES = (new State[] { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED }); + } + + private State(String s, int i) { + super(s, i); + } + } + + /** + * 一系列 构造方法 ------------------------------------------------------ + * 可以看出来,其中都调用了init()方法,这也是一个约定俗成的规矩, 即,如果要在 new 时进行一些初始化操作,那么请将初始化操作单独写在 + * init()方法中,然后在构造函数中调用该 init()方法 + */ + public Thread() { + daemon = false; + stillborn = false; + threadLocals = null; + inheritableThreadLocals = null; + threadStatus = 0; + blockerLock = new Object(); + init(null, null, (new StringBuilder()).append("Thread-").append(nextThreadNum()).toString(), 0L); + } + + public Thread(Runnable runnable) { + daemon = false; + stillborn = false; + threadLocals = null; + inheritableThreadLocals = null; + threadStatus = 0; + blockerLock = new Object(); + init(null, runnable, (new StringBuilder()).append("Thread-").append(nextThreadNum()).toString(), 0L); + } + + Thread(Runnable runnable, AccessControlContext accesscontrolcontext) { + daemon = false; + stillborn = false; + threadLocals = null; + inheritableThreadLocals = null; + threadStatus = 0; + blockerLock = new Object(); + init(null, runnable, (new StringBuilder()).append("Thread-").append(nextThreadNum()).toString(), 0L, + accesscontrolcontext); + } + + public Thread(ThreadGroup threadgroup, Runnable runnable) { + daemon = false; + stillborn = false; + threadLocals = null; + inheritableThreadLocals = null; + threadStatus = 0; + blockerLock = new Object(); + init(threadgroup, runnable, (new StringBuilder()).append("Thread-").append(nextThreadNum()).toString(), 0L); + } + + public Thread(String s) { + daemon = false; + stillborn = false; + threadLocals = null; + inheritableThreadLocals = null; + threadStatus = 0; + blockerLock = new Object(); + init(null, null, s, 0L); + } + + public Thread(ThreadGroup threadgroup, String s) { + daemon = false; + stillborn = false; + threadLocals = null; + inheritableThreadLocals = null; + threadStatus = 0; + blockerLock = new Object(); + init(threadgroup, null, s, 0L); + } + + public Thread(Runnable runnable, String s) { + daemon = false; + stillborn = false; + threadLocals = null; + inheritableThreadLocals = null; + threadStatus = 0; + blockerLock = new Object(); + init(null, runnable, s, 0L); + } + + public Thread(ThreadGroup threadgroup, Runnable runnable, String s) { + daemon = false; + stillborn = false; + threadLocals = null; + inheritableThreadLocals = null; + threadStatus = 0; + blockerLock = new Object(); + init(threadgroup, runnable, s, 0L); + } + + public Thread(ThreadGroup threadgroup, Runnable runnable, String s, long l) { + daemon = false; + stillborn = false; + threadLocals = null; + inheritableThreadLocals = null; + threadStatus = 0; + blockerLock = new Object(); + init(threadgroup, runnable, s, l); + } + + private void init(ThreadGroup threadgroup, Runnable runnable, String s, long l) { + init(threadgroup, runnable, s, l, null); + } + + /** + * 初始化线程 + */ + private void init(ThreadGroup threadgroup, Runnable runnable, String name, long l, + AccessControlContext accesscontrolcontext) { + + // 参数校验,线程name不能为null + if (name == null) + throw new NullPointerException("name cannot be null"); + this.name = name.toCharArray(); + // 当前线程就是该线程的父线程 + Thread parent = currentThread(); + SecurityManager securitymanager = System.getSecurityManager(); + if (threadgroup == null) { + if (securitymanager != null) + threadgroup = securitymanager.getThreadGroup(); + if (threadgroup == null) + threadgroup = parent.getThreadGroup(); + } + threadgroup.checkAccess(); + if (securitymanager != null && isCCLOverridden(getClass())) + securitymanager.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); + threadgroup.addUnstarted(); + // 守护线程、优先级等设置为父线程的对应属性 + group = threadgroup; + daemon = parent.isDaemon(); + priority = parent.getPriority(); + if (securitymanager == null || isCCLOverridden(parent.getClass())) + contextClassLoader = parent.getContextClassLoader(); + else + contextClassLoader = parent.contextClassLoader; + inheritedAccessControlContext = accesscontrolcontext == null ? AccessController.getContext() + : accesscontrolcontext; + target = runnable; + setPriority(priority); + if (parent.inheritableThreadLocals != null) + // 创建线程共享变量副本 + inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); + stackSize = l; + // 分配线程id + tid = nextThreadID(); + } + + public synchronized void start() { + //假若当前线程初始化还未做好,不能start,0->NEW状态 + if (threadStatus != 0) + throw new IllegalThreadStateException(); + + //通知group该线程即将启动,group的未启动线程数量减1 + group.add(this); + + boolean started = false; + try { + // 调用native的start0()方法 启动线程,启动后执行run()方法 + start0(); + started = true; + } finally { + try { + //启动不成功,group设置当前线程启动失败 + if (!started) { + group.threadStartFailed(this); + } + } catch (Throwable ignore) { + + } + } + } + + private native void start0(); + + public void run() { + if (target != null) + target.run(); + } + + /** + * 请求终止线程。interrupt不会真正停止一个线程,它仅仅是给这个线程发了一个信号, + * 告诉它要结束了,具体要中断还是继续运行,将由被通知的线程自己处理 + */ + public void interrupt() { + if (this != Thread.currentThread()) + checkAccess(); + synchronized (blockerLock) { + Interruptible b = blocker; + if (b != null) { + interrupt0(); + b.interrupt(this); + return; + } + } + interrupt0(); + } + + private native void interrupt0(); +} +``` +之前一直对线程状态 及 状态切换的概念模糊不清,现在通过源码中对线程状态的定义,我们可以画张图来重新回顾一下,以使我们对其有更加深刻的理解。 + +![avatar](/images/JDK1.8/ThreadStatusChange.png) \ No newline at end of file diff --git a/docs/JDK/ThreadLocal.md b/docs/JDK/ThreadLocal.md new file mode 100644 index 0000000..753e53e --- /dev/null +++ b/docs/JDK/ThreadLocal.md @@ -0,0 +1 @@ +努力编写中... \ No newline at end of file diff --git a/images/JDK1.8/ThreadStatusChange.png b/images/JDK1.8/ThreadStatusChange.png new file mode 100644 index 0000000..23657d2 Binary files /dev/null and b/images/JDK1.8/ThreadStatusChange.png differ