Java线程中的run和start方法

刚开始接触线程的时候,只是生硬的记住了如果要启动一个线程必须调用该线程的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方法的简单介绍就这么多吧,限于个人能力有限文章难免有错误疏忽之处还请多多指教。

本文地址www.sunnyang.com/212.html

评论

您确定要删除吗?删除之后不可恢复