盘一盘 Thread源码
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
继承关系图
线程的创建方式有很多种。常用的有:继承Thread(),重写该类的run()方法;实现Runnable接口,并重写该接口的run()方法。
其实Thread类本身也是实现了Runnable接口,而run()方法最先是在Runnable接口中定义的方法。
主要属性
// 线程的名称
private volatile char name[]; // 线程的优先级
private int priority; // 是否是单步执行
private boolean single_step; // 是否是守护线程
private boolean daemon = false; // JVM虚拟机的状态
private boolean stillborn = false; // 将会被执行的 Runnable
private Runnable target; // 当前线程的组
private ThreadGroup group; // 当前线程的上下文
private ClassLoader contextClassLoader; // 当前线程继承的访问控制权限
private AccessControlContext inheritedAccessControlContext; // 默认线程的自动编号
private static int threadInitNumber;
// 得到下个thread ID
private static synchronized int nextThreadNum() {
return threadInitNumber++;
} // 与当前线程有关的ThreadLocal值
ThreadLocal.ThreadLocalMap threadLocals = null; // 与当前线程相关的InheritableThreadLocal值。
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; // 该线程请求的堆栈大小 默认一般为空 JVM自行分配
private long stackSize; // 当前线程终止后,JVM的私有状态
private long nativeParkEventPointer; // 当前线程的专属ID
private long tid; // 用来生成 thread ID
private static long threadSeqNumber; // 线程状态,0代表线程未启动 Runable
private volatile int threadStatus = 0; // 中断阻塞器:当线程发生IO中断时,需要在线程被设置为中断状态后调用该对象的interrupt方法
volatile Object parkBlocker; // 阻塞器锁,主要用于线程中断
private volatile Interruptible blocker;
private final Object blockerLock = new Object(); // 阻断锁
void blockedOn(Interruptible b) {
synchronized (blockerLock) {
blocker = b;
}
} // 线程优先级 最低优先级
public final static int MIN_PRIORITY = 1; // 线程优先级 默认优先级
public final static int NORM_PRIORITY = 5; // 线程优先级 最高优先级
public final static int MAX_PRIORITY = 10;
构造方法
// init方法相关参数
// g 线程组
// target 实现 Runnable接口类对象,就是调用 run方法的目标对象
// name 线程名称
// stackSize 栈的大小 该值对JVM而言只是一个建议,JVM会动态选择更合适的值
// acc 访问控制权限
private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name.toCharArray(); // 设置当前线程为该线程的父线程
Thread parent = currentThread(); // 获取系统的security
SecurityManager security = System.getSecurityManager(); // 没有指定线程组的话,创建的所有线程属于相同的线程组。
if (g == null) {
// 先将secuity的线程组赋给新线程的线程组
if (security != null) {
g = security.getThreadGroup();
} // 如果还是为空,则设为父线程的线程组
if (g == null) {
g = parent.getThreadGroup();
}
}
// 检查当前线程是否有修改权限
g.checkAccess(); // 授权
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(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);
if (parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); // 分配线程栈的大小
this.stackSize = stackSize; // 分配线程Id ThreadID是由JVM分配的,并不是系统的真正线程ID
tid = nextThreadID();
} private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
init(g, target, name, stackSize, null);
} public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
} public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
} Thread(Runnable target, AccessControlContext acc) {
init(null, target, "Thread-" + nextThreadNum(), 0, acc);
} public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
} public Thread(String name) {
init(null, null, name, 0);
} public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
} public Thread(Runnable target, String name) {
init(null, target, name, 0);
} public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
} public Thread(ThreadGroup group, Runnable target, String name,
long stackSize) {
init(group, target, name, stackSize);
}
native方法
// 获得当前线程
public static native Thread currentThread(); // 使当前线程从 运行状态Running 变为 就绪状态 Runnable
public static native void yield(); // 使当前线程进入休眠状态
public static native void sleep(long millis) throws InterruptedException; // 使线程进入就绪状态 Runnable
private native void start0(); // 判断线程是否为中断状态
private native boolean isInterrupted(boolean ClearInterrupted); // 判断线程是否存活
public final native boolean isAlive(); // 获取所有线程列表
private native static StackTraceElement[][] dumpThreads(Thread[] threads);
private native static Thread[] getThreads(); // 设置线程优先等级
private native void setPriority0(int newPriority); // 停止线程 该方法已被弃用
private native void stop0(Object o); // 线程暂停
private native void suspend0(); // 线程继续执行
private native void resume0(); // 线程中断
private native void interrupt0(); // 设置线程名
private native void setNativeName(String name);
这里不得不说和线程相关的几个Object Native方法。
// 随机唤醒在此对象监视器(锁)上等待的单个线程。
public final native void notify(); // 唤醒所有等待在该对象上的线程。
public final native void notifyAll(); // 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法
public final void wait() throws InterruptedException {
wait(0);
} // 超时等待一段时间,这里的参数是毫秒,也就是等待长达n毫秒,如果没有通知就超时返回。
public final native void wait(long timeout) throws InterruptedException;
关键方法
start() 启动线程
public synchronized void start() {
// 判断线程状态是否启动,不允许同一线程启动2次!
if (threadStatus != 0)
throw new IllegalThreadStateException(); // 向线程组中添加当前线程
group.add(this); // 使线程进入就绪状态 Runnable
boolean started = false;
try {
start0();
started = true;
} finally {
try {
// 若线程启动失败,则通知该线程组,回滚线程组状态
// 该线程被视为线程组的未启动成员,并允许后续尝试启动该线程。
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
checkAccess() 检查当前线程是否有修改权限,该方法在线程状态变更前多次被调用
public final void checkAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
// 通过Java安全管理器检查当前线程是否有修改权限
security.checkAccess(this);
}
}
run() 使线程从就绪状态 Runnable转化为运行状态 Running -todo线程启动过程中由start到run的过程非常复杂。
public void run() {
// 调用 run方法的目标对象
if (target != null) {
target.run();
}
}
exit() 该方法 run方法执行完成后调用,在线程结束退出之前进行清理工作。
private void exit() {
// 释放资源
if (group != null) {
group.threadTerminated(this);
group = null;
} target = null; threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
@Deprecated
public final void stop() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
checkAccess();
if (this != Thread.currentThread()) {
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
}
} if (threadStatus != 0) {
resume(); // Wake up thread if it was suspended; no-op otherwise
} stop0(new ThreadDeath());
}
interrupt() 中断线程
public void interrupt() {
if (this != Thread.currentThread())
checkAccess(); synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
// 线程优先级范围仅分 1~10 级
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
} public final int getPriority() {
return priority;
}
public final void join() throws InterruptedException {
join(0);
} 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;
}
}
}
setDaemon() 将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
public final void setDaemon(boolean on) {
checkAccess();
// 该方法必须在启动线程前调用
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
盘一盘 Thread源码的更多相关文章
- 从Thread.start()方法看Thread源码,多次start一个线程会怎么样
这篇文章作为Thread类源码剖析的补充,从一个侧面来看Thread源码.也解答了面试高频问题:"多次start一个线程会怎么样?" 答案是:java.lang.IllegalTh ...
- java 并发编程——Thread 源码重新学习
Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...
- Handler、Looper、MessageQueue、Thread源码分析
关于这几个之间的关系以及源码分析的文章应该挺多的了,不过既然学习了,还是觉得整理下,印象更深刻点,嗯,如果有错误的地方欢迎反馈. 转载请注明出处:http://www.cnblogs.com/John ...
- Thread源码分析
本文为转载,请珍惜别人的劳动成果,注明转载地址:http://www.cnblogs.com/gw811/archive/2012/10/15/2724602.html 1.Runnable接口源码: ...
- Thread源码剖析
前言 昨天已经写了: 多线程三分钟就可以入个门了! 如果没看的同学建议先去阅读一遍哦~ 在写文章之前通读了一遍<Java 核心技术 卷一>的并发章节和<Java并发编程实战>前 ...
- Thread源码分析-java8
1.Thread特性分析 守护线程Daemon 定性:支持性线程,主要用于程序中后台调度以及支持性工作. 当JVM中不存在Daemon线程时,JVM将会退出. 将一个线程设定为Daemon的方法: 调 ...
- Java中Thread源码剖析
本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 关于线程,用很长时间了,主线程下的子线程去做一些事情,就是一个代理模式,主线程分代理权给子线程,子线 ...
- 并发编程学习笔记(七、Thread源码分析)
目录: 常见属性 构造函数 start() run() 常见属性: /** * 线程名称 */ private volatile String name; /** * 线程优先级 */ private ...
- java Thread源码分析(二)
一.sleep的使用 public class ThreadTest { public static void main(String[] args) throws InterruptedExcept ...
随机推荐
- 2019-10-18-dotnet-文件读写务必注意事项
title author date CreateTime categories dotnet 文件读写务必注意事项 lindexi 2019-10-18 08:42:53 +0800 2019-10- ...
- 基于MaxCompute的数仓数据质量管理
声明 本文中介绍的非功能性规范均为建议性规范,产品功能无强制,仅供指导. 参考文献 <大数据之路——阿里巴巴大数据实践>——阿里巴巴数据技术及产品部 著. 背景及目的 数据对一个企业来说已 ...
- @codeforces - 455E@ Function
目录 @description@ @solution@ @accepted code@ @details@ @description@ 已知 a 序列,并给定以下关系: \[\begin{cases} ...
- Android SwipeActionAdapter结合Pinnedheaderlistview实现复杂列表的左右滑动操作
在上一篇博客<Android 使用SwipeActionAdapter开源库实现简单列表的左右滑动操作>里,已经介绍了利用SwipeActionAdapter来左右滑动操作列表: 然,有时 ...
- git学习一——Pro-Git
1.配置用户名,邮箱 git config --global user.name "Mike" git config --global user.email Mike@exampl ...
- C运行时库函数和API函数的区别和联系
C运行时库函数 C运行时库函数是指C语言本身支持的一些基本函数,通常是汇编直接实现的. API函数 API函数是操作系统为方便用户设计应用程序而提供的实现特定功能的函数,API函数也是C语言的函 ...
- 2012-4-2 通过MdiParent设置窗体最前
SentenceForm form = new SentenceForm(); form.MdiParent = this; form.Show(); //form.MdiParent = this; ...
- ubuntu14.04本地域名服务器配置
dnsmasq 1 修改dnsmasq配置文件/etc/dnsmasq.conf # Change this line if you want dns to get its upstream serv ...
- JavaScript引用类型和基本类型的区别
JavaScript变量可以用来保存的两种类型的值:基本类型值和引用类型值. 基本类型值有5种类型:undefined,null,boolean,number,string 引用类型值有两种类型:函数 ...
- Treap(树堆)入门
作者:zifeiy 标签:Treap 首先,我么要知道:Treap=Tree+Heap. 这里: Tree指的是二叉排序树: Heap指的是堆. 所以在阅读这篇文章之前需要大家对 二叉查找树 和 堆( ...