面试突击:为什么Start方法不能重复调用?而Run方法却可以?

开发 前端
初学线程时,总是将 run 方法和 start 方法搞混,虽然二者是完全不同的两个方法,但刚开始使用时很难分清,原因就是因为初次使用时效果貌似是一样的.

作者 | 磊哥

来源 | Java面试真题解析(ID:aimianshi666)

转载请联系授权(微信ID:GG_Stone)

初学线程时,总是将 run 方法和 start 方法搞混,虽然二者是完全不同的两个方法,但刚开始使用时很难分清,原因就是因为初次使用时效果貌似是一样的,如下代码所示:

public static void main(String[] args) {
// 创建线程一
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("执行线程一");
}
});
// 调用 run 方法
thread.run();

// 创建线程二
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("执行线程二");
}
});
// 调用 start 方法
thread2.start();
}

以上程序的执行结果如下:

从上述结果可以看出,二者调用之后的执行效果都是一样,都可以成功执行任务。但是,如果在执行线程的时候,加上打印当前线程的名称就能看出二者的不同了,如下代码所示:

public static void main(String[] args) {
// 创建线程一
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 获取到当前执行线程
Thread currThread = Thread.currentThread();
System.out.println("执行线程一,线程名:" + currThread.getName());
}
});
// 调用 run 方法
thread.run();

// 创建线程二
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
// 获取到当前执行线程
Thread currThread = Thread.currentThread();
System.out.println("执行线程二,线程名:" + currThread.getName());
}
});
// 调用 start 方法
thread2.start();
}

以上程序的执行结果如下:

从上述结果我们可以看出:当调用 run 方法时,其实是调用当前主程序 main 来执行方法体的;而调用 start 方法才是真正的创建一个新线程来执行任务。

区别

1run 方法和 start 方法的第一个区别是:调用 start 方法是真正开启一个线程来执行任务,而调用 run 方法相当于执行普通方法 run,并不会开启新线程,如下图所示:

区别2

run 方法和 start 方法的第二个区别是:run 方法也叫做线程体,它里面包含了具体要执行的业务代码,当调用 run 方法时,会立即执行 run 方法中的代码(如果当前线程时间片未用完);而调用 start 方法时,是启动一个线程并将线程的状态设置为就绪状态。也就是说调用 start 方法,并不会立即执行。

区别3

因为 run 方法是普通方法,而普通方法是可以被多次调用的,所以 run 方法可以被调用多次;而 start 方法是创建新线程来执行任务,因为线程只能被创建一次,所以它们的第三个区别是:run 方法可以被调用多次,而 start 方法只能被调用一次。测试代码如下:


// 创建线程一
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 获取到当前执行的线程
Thread currThread = Thread.currentThread();
System.out.println("执行线程一,线程名:" + currThread.getName());
}
});
// 调用 run 方法
thread.run();
// 多次调用 run 方法
thread.run();

// 创建线程二
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
// 获取到当前执行的线程
Thread currThread = Thread.currentThread();
System.out.println("执行线程二,线程名:" + currThread.getName());
}
});
// 调用 start 方法
thread2.start();
// 多次调用 start 方法
thread2.start();

以上程序的执行结果如下:

从上述结果可以看出,run 方法多次调用可用正常执行,而第二次调用 start 方法时程序就报错了,提示“IllegalThreadStateException”非法线程状态异常。

为什么start不能被重复调用?

要找到这个问题的答案,就要查看 start 方法的实现源码,它的源码如下:

从 start 源码实现的第一行,我们就可以得到问题的答案,因为 start 方法在执行时,会先判断当前线程的状态是不是等于 0,也就是是否为新建状态 NEW,如果不等于新建状态,那么就会抛出“IllegalThreadStateException”非法线程状态异常,这就是线程的 start 方法不能被重复调用的原因。它的执行过程是:当线程调用了第一个 start 方法之后,线程的状态就会从新建状态 NEW,变为就绪状态 RUNNABLE,此时再次调用 start 方法,JVM 就会判断出当前的线程已经不等于新建状态,从而抛出 IllegalThreadStateException 非法线程状态异常。

总结

run 方法和 start 方法的主要区别如下:

  1. 方法性质不同:run 是一个普通方法,而 start 是开启新线程的方法。
  2. 执行速度不同:调用 run 方法会立即执行任务,调用 start 方法是将线程的状态改为就绪状态,不会立即执行。
  3. 调用次数不同:run 方法可以被重复调用,而 start 方法只能被调用一次。

start 方法之所以不能被重复调用的原因是,线程的状态是不可逆的,Thread 在 start 的实现源码中做了判断,如果线程不是新建状态 NEW,则会抛出非法线程状态异常 IllegalThreadStateException。

责任编辑:姜华 来源: Java面试真题解析
相关推荐

2020-05-12 08:56:16

Java 线程开发

2022-09-05 15:36:47

线程方法Java

2022-07-27 07:36:01

TCP可靠性

2022-01-11 06:53:23

面试重写重载

2022-01-06 06:58:19

Java 语言 Java 基础

2022-07-13 07:06:47

HTTPSHTTP协议

2020-12-30 10:04:46

userMapper接口

2022-01-24 07:01:20

安全多线程版本

2019-04-08 09:37:30

国内程序员美国程序员996.ICU

2009-08-26 16:58:12

调用C# Thread

2022-01-18 06:59:50

HashMap循环底层

2022-09-20 22:27:08

事务失效public 修饰

2022-04-18 07:36:37

TimeUnit线程休眠

2021-04-16 17:02:21

数组C++语言

2022-05-26 09:24:09

volatile懒汉模式

2022-01-27 07:02:52

JavaHashMap单线程

2022-07-25 07:07:35

TCP客户端服务器

2020-12-15 07:36:12

线程Start Run

2023-12-08 08:40:16

函数

2022-03-02 07:36:37

池化技术Java线程池
点赞
收藏

51CTO技术栈公众号