多线程 start 和 run 方法到底有什么区别?

简介:

fb53c74ca7217c8cdbf2319678001f88187f2e79

昨天栈长介绍了《Java多线程可以分组,还能这样玩!》线程分组的妙用。今天,栈长会详细介绍 Java 中的多线程 start() 和 run() 两个方法,Java 老司机请跳过,新手或者对这两个不是很理解的可以继续往下看。

首先要知道实现多线程最基本的两种方式:

1、继承 java.lang.Thread 类;

2、实现 java.lang.Runnable接口;

其中 Thread 类也是实现了 Runnable 接口,而 Runnable 接口定义了唯一的一个 run() 方法,所以基于 Thread 和 Runnable 创建多线程都需要实现 run() 方法,是多线程真正运行的主方法。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

而 start() 方法则是 Thread 类的方法,用来异步启动一个线程,然后主线程立刻返回。该启动的线程不会马上运行,会放到等待队列中等待 CPU 调度,只有线程真正被 CPU 调度时才会调用 run() 方法执行。

所以 start() 方法只是标识线程为就绪状态的一个附加方法,以下 start() 方法的源码,其中 start0() 是一个本地 native 方法。

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) {
            /* do nothing. If start0 threw a Throwable then
              it will be passed up the call stack */

        }
    }
}

请注意,start() 方法被标识为 synchronized 的,即为了防止被多次启动的一个同步操作。

那么你会问了,为什么要有两个方法,直接用一个 run() 方法不就行了吗!? 还真不行,如果直接调用 run() 方法,那就等于调用了一个普通的同步方法,达不到多线程运行的异步执行,来看下面的例子。

/**
 * 微信公众号:Java技术栈
 */

public static void main(String[] args{
    Thread thread = new Thread(() -> {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Java技术栈");
    });

    long start = System.currentTimeMillis();
    thread.start();
    System.out.println(System.currentTimeMillis() - start);

    start = System.currentTimeMillis();
    thread.run();
    System.out.println(System.currentTimeMillis() - start);
}

程序输出:

0
Java技术栈
3000
Java技术栈

从程序输出结果可以看出,启动 start 方法前后只用了 0 毫秒,而启动 run 方法则阻塞了 3000 毫秒等程序执行完再继续执行,这就是同步与异步的一个最重要的区别。

看完这篇,你应该对 start 和 run 方法有了一个大概的掌握吧,再也不怕面试官问你这两个的区别了吧!


原文发布时间为:2018-11-10

本文作者: 栈长 

本文来自云栖社区合作伙伴“Java技术栈”,了解相关信息可以关注“Java技术栈”。

相关文章
|
5天前
|
监控 测试技术 程序员
解决线程死循环问题的有效方法
作为开发者想必都清楚,多线程应用程序的开发为我们日常开发工作中提供了并发执行任务的能力,但线程死循环问题却是一个常见而令人头疼的挑战,因为线程死循环可能导致系统的不稳定性、资源浪费以及应用程序的异常运行,所以准确地定位和妥善处理线程死循环现象,并在编码阶段就避免潜在风险,成为开发人员必须面对的重要问题,线程死循环问题的解决不仅有助于提高系统的稳定性和可用性,还能优化资源利用和提升应用程序的性能,通过采取适当的预防和处理措施,开发人员能够避免线程陷入无尽的循环,并及时发现和解决潜在问题。那么本文就来分享一下关于如何处理线程死循环问题,以及如何在编码阶段规避潜在风险。
44 2
解决线程死循环问题的有效方法
|
5天前
|
Unix Linux 调度
linux线程与进程的区别及线程的优势
linux线程与进程的区别及线程的优势
|
5天前
简便的方法开线程干活并且出现等待提示
简便的方法开线程干活并且出现等待提示
14 3
|
5天前
|
调度
线程和进程的区别?
线程和进程的区别?
|
5天前
|
安全 Java
【JAVA】线程的run()和start()有什么区别?
【JAVA】线程的run()和start()有什么区别?
|
5天前
|
NoSQL
线程死循环的定位方法
线程死循环的定位方法
25 2
|
5天前
使用代理IP池实现多线程的方法
使用代理IP池实现多线程的方法
|
5天前
|
Java API 调度
【并发编程】Java线程常见方法的使用
【并发编程】Java线程常见方法的使用
|
5天前
|
Java 测试技术 Python
Python开启线程和线程池的方法
Python开启线程和线程池的方法
20 0
Python开启线程和线程池的方法
|
3天前
|
Python