IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 为什么start方法不能重复调用?而run方法却可以? -> 正文阅读

[Java知识库]为什么start方法不能重复调用?而run方法却可以?

初学线程时,总是将 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 方法才是真正的创建一个新线程来执行任务。

区别1
run 方法和 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 方法的主要区别如下:

方法性质不同:run 是一个普通方法,而 start 是开启新线程的方法。
执行速度不同:调用 run 方法会立即执行任务,调用 start 方法是将线程的状态改为就绪状态,不会立即执行。
调用次数不同:run 方法可以被重复调用,而 start 方法只能被调用一次。
start 方法之所以不能被重复调用的原因是,线程的状态是不可逆的,Thread 在 start 的实现源码中做了判断,如果线程不是新建状态 NEW,则会抛出非法线程状态异常 IllegalThreadStateException。 ?

最后
如果你觉得此文对你有一丁点帮助,点个赞。或者可以加入我的开发交流群:1025263163相互学习,我们会有专业的技术答疑解惑

如果你觉得这篇文章对你有点用的话,麻烦请给我们的开源项目点点star:http://github.crmeb.net/u/defu不胜感激 !

PHP学习手册:https://doc.crmeb.com
技术交流论坛:https://q.crmeb.com

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-02-19 01:00:55  更:2022-02-19 01:00:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 13:10:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码