线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

继承关系图

线程的创建方式有很多种。常用的有:继承Thread(),重写该类的run()方法;实现Runnable接口,并重写该接口的run()方法。

其实Thread类本身也是实现了Runnable接口,而run()方法最先是在Runnable接口中定义的方法。

主要属性

  1. // 线程的名称
  2. private volatile char name[];
  3.  
  4. // 线程的优先级
  5. private int priority;
  6.  
  7. // 是否是单步执行
  8. private boolean single_step;
  9.  
  10. // 是否是守护线程
  11. private boolean daemon = false;
  12.  
  13. // JVM虚拟机的状态
  14. private boolean stillborn = false;
  15.  
  16. // 将会被执行的 Runnable
  17. private Runnable target;
  18.  
  19. // 当前线程的组
  20. private ThreadGroup group;
  21.  
  22. // 当前线程的上下文
  23. private ClassLoader contextClassLoader;
  24.  
  25. // 当前线程继承的访问控制权限
  26. private AccessControlContext inheritedAccessControlContext;
  27.  
  28. // 默认线程的自动编号
  29. private static int threadInitNumber;
  30. // 得到下个thread ID
  31. private static synchronized int nextThreadNum() {
  32. return threadInitNumber++;
  33. }
  34.  
  35. // 与当前线程有关的ThreadLocal值
  36. ThreadLocal.ThreadLocalMap threadLocals = null;
  37.  
  38. // 与当前线程相关的InheritableThreadLocal值。
  39. ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
  40.  
  41. // 该线程请求的堆栈大小 默认一般为空 JVM自行分配
  42. private long stackSize;
  43.  
  44. // 当前线程终止后,JVM的私有状态
  45. private long nativeParkEventPointer;
  46.  
  47. // 当前线程的专属ID
  48. private long tid;
  49.  
  50. // 用来生成 thread ID
  51. private static long threadSeqNumber;
  52.  
  53. // 线程状态,0代表线程未启动 Runable
  54. private volatile int threadStatus = 0;
  55.  
  56. // 中断阻塞器:当线程发生IO中断时,需要在线程被设置为中断状态后调用该对象的interrupt方法
  57. volatile Object parkBlocker;
  58.  
  59. // 阻塞器锁,主要用于线程中断
  60. private volatile Interruptible blocker;
  61. private final Object blockerLock = new Object();
  62.  
  63. // 阻断锁
  64. void blockedOn(Interruptible b) {
  65. synchronized (blockerLock) {
  66. blocker = b;
  67. }
  68. }
  69.  
  70. // 线程优先级 最低优先级
  71. public final static int MIN_PRIORITY = 1;
  72.  
  73. // 线程优先级 默认优先级
  74. public final static int NORM_PRIORITY = 5;
  75.  
  76. // 线程优先级 最高优先级
  77. public final static int MAX_PRIORITY = 10;

构造方法

我们平时惯用new Thread()方法去创建一个线程,实际上线程初始化的过程中已经完成了很多默认的配置
  1. // init方法相关参数
  2. // g 线程组
  3. // target 实现 Runnable接口类对象,就是调用 run方法的目标对象
  4. // name 线程名称
  5. // stackSize 栈的大小 该值对JVM而言只是一个建议,JVM会动态选择更合适的值
  6. // acc 访问控制权限
  7. private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc) {
  8. if (name == null) {
  9. throw new NullPointerException("name cannot be null");
  10. }
  11. this.name = name.toCharArray();
  12.  
  13. // 设置当前线程为该线程的父线程
  14. Thread parent = currentThread();
  15.  
  16. // 获取系统的security
  17. SecurityManager security = System.getSecurityManager();
  18.  
  19. // 没有指定线程组的话,创建的所有线程属于相同的线程组。
  20. if (g == null) {
  21. // 先将secuity的线程组赋给新线程的线程组
  22. if (security != null) {
  23. g = security.getThreadGroup();
  24. }
  25.  
  26. // 如果还是为空,则设为父线程的线程组
  27. if (g == null) {
  28. g = parent.getThreadGroup();
  29. }
  30. }
  31. // 检查当前线程是否有修改权限
  32. g.checkAccess();
  33.  
  34. // 授权
  35. if (security != null) {
  36. if (isCCLOverridden(getClass())) {
  37. security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
  38. }
  39. }
  40. g.addUnstarted();
  41.  
  42. // 设置守护线程、优先等级
  43. this.group = g;
  44. this.daemon = parent.isDaemon();
  45. this.priority = parent.getPriority();
  46. if (security == null || isCCLOverridden(parent.getClass()))
  47. this.contextClassLoader = parent.getContextClassLoader();
  48. else
  49. this.contextClassLoader = parent.contextClassLoader;
  50. this.inheritedAccessControlContext =
  51. acc != null ? acc : AccessController.getContext();
  52. this.target = target;
  53. setPriority(priority);
  54. if (parent.inheritableThreadLocals != null)
  55. this.inheritableThreadLocals =
  56. ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
  57.  
  58. // 分配线程栈的大小
  59. this.stackSize = stackSize;
  60.  
  61. // 分配线程Id ThreadID是由JVM分配的,并不是系统的真正线程ID
  62. tid = nextThreadID();
  63. }
  64.  
  65. private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
  66. init(g, target, name, stackSize, null);
  67. }
  68.  
  69. public Thread() {
  70. init(null, null, "Thread-" + nextThreadNum(), 0);
  71. }
  72.  
  73. public Thread(Runnable target) {
  74. init(null, target, "Thread-" + nextThreadNum(), 0);
  75. }
  76.  
  77. Thread(Runnable target, AccessControlContext acc) {
  78. init(null, target, "Thread-" + nextThreadNum(), 0, acc);
  79. }
  80.  
  81. public Thread(ThreadGroup group, Runnable target) {
  82. init(group, target, "Thread-" + nextThreadNum(), 0);
  83. }
  84.  
  85. public Thread(String name) {
  86. init(null, null, name, 0);
  87. }
  88.  
  89. public Thread(ThreadGroup group, String name) {
  90. init(group, null, name, 0);
  91. }
  92.  
  93. public Thread(Runnable target, String name) {
  94. init(null, target, name, 0);
  95. }
  96.  
  97. public Thread(ThreadGroup group, Runnable target, String name) {
  98. init(group, target, name, 0);
  99. }
  100.  
  101. public Thread(ThreadGroup group, Runnable target, String name,
  102. long stackSize) {
  103. init(group, target, name, stackSize);
  104. }

native方法

  1. // 获得当前线程
  2. public static native Thread currentThread();
  3.  
  4. // 使当前线程从 运行状态Running 变为 就绪状态 Runnable
  5. public static native void yield();
  6.  
  7. // 使当前线程进入休眠状态
  8. public static native void sleep(long millis) throws InterruptedException;
  9.  
  10. // 使线程进入就绪状态 Runnable
  11. private native void start0();
  12.  
  13. // 判断线程是否为中断状态
  14. private native boolean isInterrupted(boolean ClearInterrupted);
  15.  
  16. // 判断线程是否存活
  17. public final native boolean isAlive();
  18.  
  19. // 获取所有线程列表
  20. private native static StackTraceElement[][] dumpThreads(Thread[] threads);
  21. private native static Thread[] getThreads();
  22.  
  23. // 设置线程优先等级
  24. private native void setPriority0(int newPriority);
  25.  
  26. // 停止线程 该方法已被弃用
  27. private native void stop0(Object o);
  28.  
  29. // 线程暂停
  30. private native void suspend0();
  31.  
  32. // 线程继续执行
  33. private native void resume0();
  34.  
  35. // 线程中断
  36. private native void interrupt0();
  37.  
  38. // 设置线程名
  39. private native void setNativeName(String name);

这里不得不说和线程相关的几个Object Native方法。

  1. // 随机唤醒在此对象监视器(锁)上等待的单个线程。
  2. public final native void notify();
  3.  
  4. // 唤醒所有等待在该对象上的线程。
  5. public final native void notifyAll();
  6.  
  7. // 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法
  8. public final void wait() throws InterruptedException {
  9. wait(0);
  10. }
  11.  
  12. // 超时等待一段时间,这里的参数是毫秒,也就是等待长达n毫秒,如果没有通知就超时返回。
  13. public final native void wait(long timeout) throws InterruptedException;
我最开始有些疑惑,为什么wait(),notify(),notifyAll()用来操作线程会定义在Object类中?
不妨我们先做一个假设:将wait、notify和线程队列都放到Thread中,那么在wait、notify的调度过程中必然要求某个Thread知道其他所有Thread的信息,显然是不合理的。
而放到对象中,让对象维护所有竞争锁线程的队列,各个线程无必然联系。
 

关键方法

start() 启动线程

  1. public synchronized void start() {
  2. // 判断线程状态是否启动,不允许同一线程启动2次!
  3. if (threadStatus != 0)
  4. throw new IllegalThreadStateException();
  5.  
  6. // 向线程组中添加当前线程
  7. group.add(this);
  8.  
  9. // 使线程进入就绪状态 Runnable
  10. boolean started = false;
  11. try {
  12. start0();
  13. started = true;
  14. } finally {
  15. try {
  16. // 若线程启动失败,则通知该线程组,回滚线程组状态
  17. // 该线程被视为线程组的未启动成员,并允许后续尝试启动该线程。
  18. if (!started) {
  19. group.threadStartFailed(this);
  20. }
  21. } catch (Throwable ignore) {
  22. /* do nothing. If start0 threw a Throwable then
  23. it will be passed up the call stack */
  24. }
  25. }
  26. }

checkAccess() 检查当前线程是否有修改权限,该方法在线程状态变更前多次被调用

  1. public final void checkAccess() {
  2. SecurityManager security = System.getSecurityManager();
  3. if (security != null) {
  4. // 通过Java安全管理器检查当前线程是否有修改权限
  5. security.checkAccess(this);
  6. }
  7. }

run()  使线程从就绪状态 Runnable转化为运行状态 Running   -todo线程启动过程中由start到run的过程非常复杂。

  1. public void run() {
  2. // 调用 run方法的目标对象
  3. if (target != null) {
  4. target.run();
  5. }
  6. }

exit()  该方法 run方法执行完成后调用,在线程结束退出之前进行清理工作。

  1. private void exit() {
  2. // 释放资源
  3. if (group != null) {
  4. group.threadTerminated(this);
  5. group = null;
  6. }
  7.  
  8. target = null;
  9.  
  10. threadLocals = null;
  11. inheritableThreadLocals = null;
  12. inheritedAccessControlContext = null;
  13. blocker = null;
  14. uncaughtExceptionHandler = null;
  15. }
stop() stop方法是不安全的,它会立即停止线程执行,线程的后续执行不连贯。可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。故被标记为@Deprecated

  1. @Deprecated
  2. public final void stop() {
  3. SecurityManager security = System.getSecurityManager();
  4. if (security != null) {
  5. checkAccess();
  6. if (this != Thread.currentThread()) {
  7. security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
  8. }
  9. }
  10.  
  11. if (threadStatus != 0) {
  12. resume(); // Wake up thread if it was suspended; no-op otherwise
  13. }
  14.  
  15. stop0(new ThreadDeath());
  16. }

interrupt()  中断线程

  1. public void interrupt() {
  2. if (this != Thread.currentThread())
  3. checkAccess();
  4.  
  5. synchronized (blockerLock) {
  6. Interruptible b = blocker;
  7. if (b != null) {
  8. interrupt0(); // Just to set the interrupt flag
  9. b.interrupt(this);
  10. return;
  11. }
  12. }
  13. interrupt0();
  14. }
setPriority()、getPriority()  设置、获取线程优先级
  1. public final void setPriority(int newPriority) {
  2. ThreadGroup g;
  3. checkAccess();
  4. // 线程优先级范围仅分 1~10 级
  5. if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
  6. throw new IllegalArgumentException();
  7. }
  8. if((g = getThreadGroup()) != null) {
  9. if (newPriority > g.getMaxPriority()) {
  10. newPriority = g.getMaxPriority();
  11. }
  12. setPriority0(priority = newPriority);
  13. }
  14. }
  15.  
  16. public final int getPriority() {
  17. return priority;
  18. }
 
join()  在当前线程中调用另一个线程的join()方法,使当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。
  1. public final void join() throws InterruptedException {
  2. join(0);
  3. }
  4.  
  5. public final synchronized void join(long millis) throws InterruptedException {
  6. long base = System.currentTimeMillis();
  7. long now = 0;
  8.  
  9. if (millis < 0) {
  10. throw new IllegalArgumentException("timeout value is negative");
  11. }
  12.  
  13. if (millis == 0) {
  14. while (isAlive()) {
  15. wait(0);
  16. }
  17. } else {
  18. while (isAlive()) {
  19. long delay = millis - now;
  20. if (delay <= 0) {
  21. break;
  22. }
  23. wait(delay);
  24. now = System.currentTimeMillis() - base;
  25. }
  26. }
  27. }

setDaemon() 将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。

  1. public final void setDaemon(boolean on) {
  2. checkAccess();
  3. // 该方法必须在启动线程前调用
  4. if (isAlive()) {
  5. throw new IllegalThreadStateException();
  6. }
  7. daemon = on;
  8. }

盘一盘 Thread源码的更多相关文章

  1. 从Thread.start()方法看Thread源码,多次start一个线程会怎么样

    这篇文章作为Thread类源码剖析的补充,从一个侧面来看Thread源码.也解答了面试高频问题:"多次start一个线程会怎么样?" 答案是:java.lang.IllegalTh ...

  2. java 并发编程——Thread 源码重新学习

    Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...

  3. Handler、Looper、MessageQueue、Thread源码分析

    关于这几个之间的关系以及源码分析的文章应该挺多的了,不过既然学习了,还是觉得整理下,印象更深刻点,嗯,如果有错误的地方欢迎反馈. 转载请注明出处:http://www.cnblogs.com/John ...

  4. Thread源码分析

    本文为转载,请珍惜别人的劳动成果,注明转载地址:http://www.cnblogs.com/gw811/archive/2012/10/15/2724602.html 1.Runnable接口源码: ...

  5. Thread源码剖析

    前言 昨天已经写了: 多线程三分钟就可以入个门了! 如果没看的同学建议先去阅读一遍哦~ 在写文章之前通读了一遍<Java 核心技术 卷一>的并发章节和<Java并发编程实战>前 ...

  6. Thread源码分析-java8

    1.Thread特性分析 守护线程Daemon 定性:支持性线程,主要用于程序中后台调度以及支持性工作. 当JVM中不存在Daemon线程时,JVM将会退出. 将一个线程设定为Daemon的方法: 调 ...

  7. Java中Thread源码剖析

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 关于线程,用很长时间了,主线程下的子线程去做一些事情,就是一个代理模式,主线程分代理权给子线程,子线 ...

  8. 并发编程学习笔记(七、Thread源码分析)

    目录: 常见属性 构造函数 start() run() 常见属性: /** * 线程名称 */ private volatile String name; /** * 线程优先级 */ private ...

  9. java Thread源码分析(二)

    一.sleep的使用 public class ThreadTest { public static void main(String[] args) throws InterruptedExcept ...

随机推荐

  1. matlab 单元最短路 Dijkstra算法 无向图

    W = [2 8 1 1 6 5 1 2 3 6 4 9 3 7 9]; S = [0 0 0 1 1 3 3 3 5 5 6 4 6 2 2];S=S+1; T = [1 3 2 4 3 4 5 6 ...

  2. 洛谷 P3768 简单的数学题 (莫比乌斯反演)

    题意:求$(\sum_{i=1}^{n}\sum_{j=1}^{n}ijgcd(i,j))mod p$(p为质数,n<=1e10) 很显然,推式子. $\sum_{i=1}^{n}\sum_{j ...

  3. SELinux 宽容模式(permissive) 强制模式(enforcing) 关闭(disabled) 几种模式之间的转换

    http://blog.sina.com.cn/s/blog_5aee9eaf0100y44q.html 在CentOS6.2 中安装intel 的c++和fortran 的编译器时,遇到来一个关于S ...

  4. @loj - 2461@ 「2018 集训队互测 Day 1」完美的队列

    目录 @description@ @solution@ @part - 0@ @part - 1@ @accepted code@ @details@ @description@ 小 D 有 n 个 ...

  5. async/await运用-前端表单弹窗验证同步书写方式(React)

    在前端项目中,我们经常会碰到这样的场景: 当前我们有一个表单需要填写,在完成表单填写后经过校验之后会弹出短信或者其他形式验证码,进行补充校验,然后一起提交给接口. 场景如下图: 当前为创建操作,编辑操 ...

  6. 树状数组(Binary Index Tree)

    一维BIT(单点更新,区间求和): Problem - 1166 #include <iostream> #include <algorithm> #include <c ...

  7. DataTable CAST 成集合后,进行自定义排序再转换回DataTable

    dt = dt.Rows.Cast<DataRow>().OrderBy(r => Convert.ToInt32(r["数量"])==0?1:0).ThenBy ...

  8. 模板—tarjan求割点

    int dfn[MAXN],low[MAXN],cnt,root; bool iscut[MAXN]; void tarjan(int x) { dfn[x]=low[x]=++cnt; ; for( ...

  9. poj 3159 Candies (dij + heap)

    3159 -- Candies 明明找的是差分约束,然后就找到这题不知道为什么是求1~n的最短路的题了.然后自己无聊写了一个heap,518ms通过. 代码如下: #include <cstdi ...

  10. cmd导入比较大的sql脚本

    osql -S jack_c -d yourdb -U sa -P 123 -i E:\user.sql 注意: sql脚本里面一定要先创建数据库或者use到某个数据库,然后再cmd执行脚本