Java中线程的run()方法和start()方法有什么区别?

Wesley13
• 阅读 567

    欢迎大家关注我的公众号,有问题可以及时和我交流。 Java中线程的run()方法和start()方法有什么区别?

    由于Java是支持单继承的(接口除外),所以我们普遍启动线程的方式都是实现Runnable接口并重写run()方法。先来看下面一个简单的实例:

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        try {
            // 睡眠3秒
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("实现Runnable接口的线程");
    }
}


public class MyRunnableTest {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("--------开始调用线程--------");
        Thread thread= new Thread(new MyRunnable());
        thread.run();
        System.out.println("--------调用线程结束--------");
    }
}

    你能猜出上面执行的顺序吗?或许你可以试着尝试用机器运行一下,把得到的结果和你的猜想进行一个验证。

    运行之前请仔细思考一下,如果run()方法启动了一个线程的话,那么在“MyRunnable”中我们设置了休眠,主线程应该继续往下执行,那么输出的结果应该就是:

--------开始调用线程--------
--------调用线程结束--------
实现Runnable接口的线程

    但是,我们来看下实际的运行结果:

--------开始调用线程--------
实现Runnable接口的线程
--------调用线程结束--------

    很显然run()方法其实是按照顺序执行的,并没有真正的启动一个线程。在解释原因之前我们先来看看下面这段代码:

Thread thread= new Thread(new MyRunnable());

    这段代码也就是构造了一个thread对象,并且把我们实现的Runnable传递了进去。我们点进源码查看一下这个构造方法。

public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

    在这里,先不需要了解构造方法的每一参数,只需要注意一下我们传递进来的“MyRunnable”它是一个Runnable对象,这里赋给了"target"。请先记住这一点,他在后面的解析中很重要。 重点来了:接下来我们再来看看所谓的线程启动的代码:

thread.run();

    我们还是点击进去源码,能看到如下的代码示例:

@Override
public void run() {
    if (target != null) {
        target.run();
    }
}

    我想看到“@Override”这个关键词,大家应该立刻想到他是一个方法的重写,然后我们发现,其实Thread类也是实现了“Runnable”接口的。这里看到“target ”其实就是我们自定义的MyRunnable,“target.run()”最终调用的方法也就是“MyRunnable.run()”。因此可以得出一个结论,run()方法并不会真正的启动一个线程,调用run()方法,就相当于调用了一个普通方法,程序还是按照顺序执行的。下图展示了调用的过程。 Java中线程的run()方法和start()方法有什么区别?     然后我们尝试正确的启动一个线程,代码如下:

public class MyRunnableTest {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("--------开始调用线程--------");
        Thread thread= new Thread(new MyRunnable());
        thread.start();
        System.out.println("--------调用线程结束--------");
    }

}

    运行结果:

--------开始调用线程--------
--------调用线程结束--------
实现Runnable接口的线程

    通过运行程序可以发现,这次的输入内容是符合我们之前的预期的。我们再次点进“start()”的源码进行查看(不用每一行都了解其原理,先大致了解即可。):

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()”跟进“start0()”的源码能够发现这个方法调用的是一个本地的方法,也就是交给底层去实现了。

private native void start0();

Java中线程的run()方法和start()方法有什么区别?

Thread.start()--->start0()--->run()

**    总的来说我们启动一个线程的话,构造好线程之后,调用“start()”方法才算真正的启动了一个线程。**     欢迎大家关注我的公众号,有问题可以及时和我交流。 Java中线程的run()方法和start()方法有什么区别?

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
Java面试系列
实现多线程的方式继承Thread类,重写run方法,调用start方法启动线程实现Runnable接口,重写run方法,调用start方法启动线程实现Callable接口,重写call方法,并用FutureTask包装,在newThread中传入FutureTask,然后调用start方
Wesley13 Wesley13
3年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这