刚开始接触线程的时候,只是生硬的记住了如果要启动一个线程必须调用该线程的start方法,可是由于刚开始不经常使用多线程方面的知识,所以渐渐的就模糊了,现在常常碰到多线程的使用,知其然知其所以然嘛,今天就从源码方面探究一下。

run方法

查看一下JDK的源码,可以看到Thread中的run方法调用的是Runnable中run:

private Runnable target;
public void run() {
if (target != null) {
target.run();
}
}

Thread中定义了一个Runnable类型的私有属性target,在不为空的情况下直接调用了Runnable的run方法,接着看Runnable源码:

public interface Runnable {
public abstract void run();
}

Runnable接口中就一个方法,一直感觉线程是非常高大上的东西,为什么到了这里会这么简单呢,大概越抽象的东西越不容易错吧,所以领导人说话向来都很抽象,呵呵。到这里大概有些恍然大悟了,怪不得两种创建线程的方式都需要实现run方法呢,很简答的一个接口回调,差不多就是这个意思。所以如果我们创建线程之后如果直接调用该线程的run方法,就跟执行其它方法一样,在主线程中顺序执行,并没有达到多线程的效果。

下面写一个简单的demo来测试一下

private class RunTask extends Thread {
public RunTask(String name) {
super(name);
}
public void run() {
System.out.println("sub:"+Thread.currentThread().getId());
System.out.println("======" + this.getName());
}
}
public void m1() {
Thread demo01 = new RunTask("demo01");
Thread demo02 = new RunTask("demo02");
demo01.run();
demo02.run();
}

下面是主方法,在控制台可以看到输出结果

public static void main(String[] args) {
MainTest main = new MainTest();
System.out.println("main:"+Thread.currentThread().getId());
main.m1();
}
//输出结果如下
//main:1
//sub:1
//======demo01
//sub:1
//======demo02

无论我们运行多少次,demo01和demo02一定是顺序执行的,并且它们的线程ID始终是相同的,这说明直接调用run方法并没有开启一个线程,只是执行了普通的方法调用。

start方法

既然前面直接调用run方法没有开启新的线程,start方法到底做了哪些工作呢,同样在Thread源码中找到start源码:

public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
start0();
if (stopBeforeStart) {
stop0(throwableFromStop);
}
}
private native void start0();

start方法调用了一个本地方法start0,本地方法调用就深入到了更底层的调用了,从这里我们就可以知道事实上是在底层开启了一个新的线程,写个简单的demo看一下效果,RunTask还是使用上面的代码

public void m2() {
Thread demo01 = new RunTask("demo01");
Thread demo02 = new RunTask("demo02");
demo01.start();
demo02.start();
}
// main方法
public static void main(String[] args) {
MainTest main = new MainTest();
System.out.println("main:" + Thread.currentThread().getId());
main.m2();
}
//程序执行结果
//main:1
//sub:9
//======demo02
//sub:8
//======demo01

如果多运行几次,我们会发现demo01和demo02并不是按顺序执行的,而且线程的ID已经与main线程的明显不同的。

还有一点就是start方法只能执行一次,如果我们在执行一次就会抛出IllegalThreadStateException异常,从上面摘出来的start方法中我们知道,Thread中有一个int类型的标识threadStatus,只要它不等于0就会抛出异常,JDK中对threadStatus的说明:

Java thread status for tools,
initialized to indicate thread 'not yet started'

简单翻译一下就是线程状态标识,初始值来标记线程还没有开始。所以当我们调用一次start方法之后threadStatus的值就发生了变化,所以如果在调用start方法就抛出异常。

关于run和start方法的简单介绍就这么多吧