我们知道启动一个线程使用的是Thread类的start()方法,但start()方法最后仍然会自动调用run()方法,那为什么不直接使用run()方法呢?
错误样例
先看下面这个例子:
public class test {
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(()->{
System.out.println(Thread.currentThread().getName());
});
thread.setName("线程2");
thread.run();
thread.join();
System.out.println(Thread.currentThread().getName());
}
}
首先创建了一个名称为“线程2”的子线程,这里我们使用run()方法去运行这个线程,正常结果应该是线程2和main线程一起输出,但是结果如下:
main
main
这就说明我们是不能使用run()方法去替代start()方法的。
原因
首先我们需要明白一个问题:JAVA真的可以开启线程吗?
答案是否定的。Java是没有权限去开启线程、操作硬件的,它通过调用底层的C++代码来开启一个新的线程。查看start()方法源码,我们会发现它调用了一个native修饰的start0()方法。
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0(); // 调用本地方法去开启一个线程
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
// 本地方法start0
private native void start0();
这里说明了java是不能开启线程的,只能通过本地方法start0()启动线程,而当我们直接使用run()方法时,既然线程都还没有开启,又怎么会得到正常的结果呢?
当我们调用run()方法时,线程并没有开启,这就相当于我们只是单纯地通过对象去调用一个普通方法而已,此时执行的线程还是主线程,并且当前只有主线程在执行(不算上守护线程),因此得到两个main是理所当然了。
而我们使用start()方法时,线程已经开启,因此就得到了正确的结果。
public class test {
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(()->{
System.out.println(Thread.currentThread().getName());
});
thread.setName("线程2");
thread.start();
thread.join();
System.out.println(Thread.currentThread().getName());
}
}
结果如下:
线程2
main
总结
当我们new了一个 Thread时,线程就进入了新建状态。调⽤ start() ⽅法,会启动⼀个线程并使线程进⼊了就绪状态,当分配到时间⽚后就可以开始运⾏了。 start() 会执⾏线程的相应准备⼯作,然后⾃动执⾏ run() ⽅法的内容,这是真正的多线程⼯作。 但是,直接执⾏ run() ⽅法,会把 run()⽅法当成⼀个 main 线程下的普通⽅法去执⾏,并不会在某个线程中执⾏它,所以这并不是多线程⼯作。
说白了就是一句话:调⽤ start() ⽅法⽅可启动线程并使线程进⼊就绪状态,直接执⾏ run() ⽅法的话不会以多线程的⽅式执⾏。