Thread源码详解(详细猜测 一)
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives();
static {
registerNatives();
}
//如果你点击这个东西,会发现这两个东西就是在来回乱跳.并不会更深的跳转.
//这是因为这是一个本地方法'用C或者C++实现的'.
//java虚拟机并不是用java写的,而是用C语言写的.所以他是要依靠本地方法去执行一些底层的知识的.这被称作Native方法,就是本地的方法.
本地方法是联系java程序和底层主机操作系统的连接方法
要想深入理解可以看如下的文章:
我简述一下,这个registerNatives()有别于其他方法.
本地方法使用其他语言实现并保存在动态链接库中
那么这个方法是干什么用的?
有名字我们可以看出来,这个本地方法实际上就应该是将要用到的本地方法注册到动态链接库中(除了自己).
然后java才可以调用.
为什么要注册?
一个java程序要想调用一个本地方法,需要执行两个步骤:
- 通过System.loadLibrary()将本地方法加载进内存.
- 当java需要调用本地发方法时,虚拟机啊在加载的动态文件中定位并连接被调用的本地方法.
这个registerNatives()方法实际上就是对第二部的一个实现,执行了这个步骤之后,java就可以直接调用本地方法了.
实际上虚拟机也能做到上述所说的第二埗,这个方法只是会让这一切更加的有效率.
原为对于概念有更深的讲解,我们但是我们只需要知道到这里就可以了.
可以理解为,这是让Thread可以直接调用本地方法的方法
接下来是一些变量,之后会用到
/* Whether or not to single_step this thread. */
private boolean single_step;
//是否时守护线程
/* Whether or not the thread is a daemon thread. */
private boolean daemon = false;
//虚拟机状态,是不是存活?
/* JVM state */
private boolean stillborn = false;
//要执行的任务,就是RUN()中的内容.实际上这也证明了Thread实现了一个Runnable对象
/* What will be run. */
private Runnable target;
//线程组,表示线程的一个集合
/* The group of this thread */
private ThreadGroup group;
//ClassLoader(也许用来打印字节流的?)
/* The context ClassLoader for this thread */
private ClassLoader contextClassLoader;
//java安全模式????可以看java安全模型介绍了解
/* The inherited AccessControlContext of this thread */
private AccessControlContext inheritedAccessControlContext;
这就是一些变量.
接着是一个普通的方法.
/* For autonumbering anonymous threads. */
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
//给匿名的thrad一个值
我们可以用一个小实验证明这一点
public class HOMEWORK1 {
public static void main(String[] args) {
for (int i = 0; i <3 ; i++) {
//每次创建一个新对象
home home = new home();
home.start();
}
}
}
class home extends Thread{
public void run(){
System.out.println(Thread.currentThread());
}
}
输出的值
Thread[Thread-2,5,main]
Thread[Thread-1,5,main]
Thread[Thread-0,5,main]
我们只要注意Thread后面的数字就可以,在后面两个我就猜出来一个调用线程main.那个5是干嘛的没猜出来.
之后还有几个变量,新不猜ThreadLocal有关
threadlocal而是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据,
/**
* This class provides thread-local variables. These variables differ from
* their normal counterparts in that each thread that accesses one (via its
* {@code get} or {@code set} method) has its own, independently initialized
* copy of the variable. {@code ThreadLocal} instances are typically private
* static fields in classes that wish to associate state with a thread (e.g.,
* a user ID or Transaction ID).
*/
(机翻大师)
/*
该类提供线程本地变量。这些变量与普通的对应变量不同,因为每个访问一个变量的线程(通过其{@code get}或{@code set}方法)都有自己独立的变量初始化副本。{@code ThreadLocal}实例通常是私有的
希望将状态与线程关联的类中的静态字段(例如,用户ID或事务ID)。
*/
意思就是为每个线程创建一块绝对私有的领域,让这个领域中的内容被线程独享.
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
/*
* 此线程请求的堆栈大小,如果创建者没有指定堆栈大小,则为0。VM可以对这个数字做任何它想做的事情;一些vm会忽略它。
*/
private long stackSize;
/*
* 私有jvm状态,在本线程终止后仍然存在。
*/
private long nativeParkEventPointer;
/*
* Thread ID
*/
private long tid;
/*用于生成线程ID*/
/* For generating thread ID */
private static long threadSeqNumber;
/* Java thread status for tools,
* initialized to indicate thread 'not yet started'
*/
//工具的Java线程状态,初始化以指示线程“尚未启动”
private volatile int threadStatus = 0;
之后是几个本地方法
public static native void sleep(long millis) throws InterruptedException;//睡眠
public static native void yield();//建议让出进程
public static native Thread currentThread();//这个线程的名字
之后时sleep()的一个扩展方法
public static void sleep(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++;
}//输入的纳秒值,如果大于半毫秒执行一毫秒
//可以理解为四舍五入,如果没有设定毫秒,那么就按照进一法来.
1毫秒(ms)=1000000纳秒(ns)
sleep(millis);//调用本地方法
}
之后再往下就是一个init()方法,是实例化线程的(非常复杂就不全高上来了)
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals)
我们只要知道,实际上在Thread中实际上是依靠init实例化线程对象的,而不是用Thread对象.
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
然后调用这样的init,实现对于线程的实例化
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
这些东东之后就是start()方法
public synchronized void start() {
/**
* 对于由VM创建/设置的主方法线程或“系统”组线程,不会调用此方法。将来向这个方法添加的任何新功能可能也必须添加到VM中。
零状态值对应于状态“NEW”。
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* 通知组此线程即将启动,以便可以将其添加到组的线程列表中,并且可以减少组的未启动计数。 */
group.add(this);
//为了防止出现线程启动时失败的情况
boolean started = false;//
try {
start0();//启动,这个是本地方法
started = true;//置为true如果出现问题,就执行不了下面得赋值语句,start会保持为false
} 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 */
}
}
}
然后是run方法,其本事Native方法,这个只是外面套了一层java代码.
之后是一个私有的private类,这个是为了在线程真的结束之前,将其中所有的值全部清除.
private void exit() {
if (group != null) {
group.threadTerminated(this);
group = null;
}
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
/* Speed the release of some of these resources */
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}