在面试中,很多童鞋都会被问到关于多线程的问题,以创建方式为引,随即便抛出如何启动一个线程,顺藤摸瓜问出start()和run()的区别。当然了貌似这种问题都被问烂了,我也不记得当初是怎么回答的了,但可以肯定回答得不怎么样...
正确的启动方式——start()
如下述代码执行结果所示,输出的结果为 main、Thread-0(默认子线程名称为Thread+自增)。
run()方法直接输出为当前线程,而非子线程。start()方法执行后,结果为子线程输出。
public static void main(String[] args) {
Runnable runnable = () ->{
System.out.println(Thread.currentThread().getName());
};
runnable.run();
new Thread(runnable).start();
}
由此可知,start()方为线程正确启动,因为我们的本意是要新建一个线程然后把它启动起来。其实就是因为run方法它只是一个普通的java方法,它并不具有启动线程的作用。为什么这么说呢?我们来看下官网是如何阐述的:
上面的意思用简单的话来说就是:如果直接调用Thread的run(),而不选择覆盖它,则不执行任何操作并返回,虽然Thread类中的run方法实现了Runable接口,但是其本身并不具有启动线程的意义,这和Runable接口中的run方法没有什么实质的区别。
多次调用start()方法
多次调用start()方法,首次会使线程进入Runnable状态,再次调用会抛出异常。下述为Thread的部分源码:
//决定该线程的状态
private volatile int threadStatus = 0;
......
//start()中首行便是判断当前线程的状态是否未0 (未开始值)
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
......
}
由此可知,在执行start()方法的时候,会有volatile(同步)的int修饰变量,当线程已经调用过start()方法时,threadStatue的值将不再为0,所以再次调用start()的时候会触发判断,并抛出异常。
既然start() 方法会调用run()方法,为什么我们选择调用start()方法,而不是直接调用run()方法呢?
正如上述所说的,单独调用run(),就像单纯的java方法调用一样,其调用方为当前线程,而非创建的子线程,与我们的目的所违背。正确的启动线程方式是start()方法,调用start()方法才会使线程走正常的生命周期。
总结
本篇文章进对run()方法和start()方法进行了简单的对比,其意义是要体现线程的正确启动方式。