0%

启动线程的正确姿势

我们都知道Java多线程的实质是调用Thread类的run()方法,每次我们开启新线程都得调用start()方法,那我们能不能直接调用run()方法进行启动线程呢?

start()和run()的比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

/**
* @author gelong
* @date 2020/6/1 21:39
*/
public class StartAndRunMethod {

public static void main(String[] args) {
Runnable runnable = () -> {
System.out.println(Thread.currentThread().getName());
};
runnable.run();
new Thread(runnable).start();
}
}

startthread.jpg

从运行结果我们可以看出使用start()方法才能创建出新线程,使用run()方法只是在main线程里面调用一个普通的方法而已。

start()方法原理解读

我们先来看的一段代码

1
2
3
4
5
6
7
8
9
10
11
12
13

/**
* @author gelong
* @date 2020/6/1 23:09
*/
public class CantStartTwice {

public static void main(String[] args) {
Thread thread = new Thread();
thread.start();
thread.start();
}
}

cantstarttwice.jpg

我们调用了两次start()方法,结果抛出了线程状态不符合的异常。为什么会抛出这样的异常呢,我们来看看start()方法的源码。

threadexception.jpg

从start()的源码我们可以看到线程刚刚new实例但是还没有启动的时候的状态未0,当线程已经调用start()方法启动线程后,线程的状态已经不为0了,此时再调用一次start()方法就会抛出异常。

startsource.jpg

继续分析start()方法我们会发现start方法的执行流程如下:

  • 检查线程状态,只有NEW状态下的线程才能继续,否则会抛出IllegalThreadStateException
  • 被加入线程组
  • 调用start0()方法启动线程

注意点:start0()是native类型的,它的底层是c++实现的。start方法是被synchronized修饰的方法,可以保证线程安全,由JVM创建的main方法线程和system组线程,并不会通过start来启动。

run()方法原理解读

runsource.jpg

没啥好说的了,经典三行代码。

总结

Java启动多线程的方法是通过调用Thread类的start()方法且不能调用多次,直接调用Thread类的run()方法并不能启动线程,和我们在main里面调用类的普通方法没什么区别。