首先概述一下Java中线程创建的原理,线程的创建是在jvm中创建的,不同的jvm有不同的创建方式,(比如说我们最常用的Oracle的hotspot jvm)而在jvm下,还会判断当前的系统是什么样的系统,从而最终由系统来实现创建线程。
在Java中创建一个线程的方法有几种,本文主要是讲一下通过线程对象创建以后,通过调用start方法开启一个线程的具体情况,至于创建的几种方式,本文不再叙述。
我们首先看一下Thread类的构造方法源码:
/**
* Allocates a new {@code Thread} object. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, target, gname)}, where {@code gname} is a newly generated
* name. Automatically generated names are of the form
* {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
*
* @param target
* the object whose {@code run} method is invoked when this thread
* is started. If {@code null}, this classes {@code run} method does
* nothing.
*/
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
构造方法会直接调用私有的init方法,在init方法体中有这样一句:this.target = target;(target即为构造方法中传递进来的target对象),这样构造方法传递的Runnable对象就成为了thread对象的全局变量。
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();
// ... Some oth stmts...
this.target = target;
// ... Some oth stmts...
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
在当我们调用线程的start方法时,会通过调用native的start方法,通过系统去创建一个新的线程,随后在这个线程中调用thread的run方法,我们看一下run方法的源码:
@Override
public void run() {
if (target != null) {
target.run();
}
}
所以在线程创建后,会判断target对象是否为空,不为空的情况下会调用Runnable对象的run方法。我们可以得出以下的结论:
- 将Runnable对象作为构造函数的参数,最终在线程执行时,会调用该对象的run方法。
- 如果Thread类复写了run方法,并修改了原有的run方法,将不会调用Runnable对象的run方法。
下一篇:ThreadPoolExecutor详解:https://my.oschina.net/u/3760321/blog/1615152