开发者社区> 推荐码发放> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

Java 多线程启动为什么调用 start() 方法而不是 run() 方法?

简介:
+关注继续查看

Java 多线程启动为什么调用 start() 方法而不是 run() 方法?

多线程在工作中多多少少会用到,我们知道启动多线程调用的是 start() 方法,而不是 run() 方法,你知道原因吗?

在探讨这个问题之前,我们先来了解一些多线程的基础知识~

线程的状态
Java 中,定义了 6 种线程状态,在 Thread 类可以找到:

// 为了节约空间,我删除了注释
public enum State {

   NEW,//初始状态
   RUNNABLE,//运行状态
   BLOCKED,// 阻塞状态
   WAITING,//等待状态
   TIMED_WAITING,//超时等待状态
   TERMINATED;//终止状态

}
这 6 种状态之间的关联,可以看下面这张图:

这张图描述的还是非常详细的,结合这张图,来说说这几种状态分别代表着什么意思:

1、NEW 表示线程创建成功,但没有运行,在 new Thread 之后,没有 start 之前,线程都处于 NEW 状态;
2、RUNNABLE 表示线程正在运行中,当我们运行 strat 方法,子线程被创建成功之后,子线程的状态变成 RUNNABLE;
3、TERMINATED 表示线程已经运行结束,子线程运行完成、被打断、被中止,状态都会从 RUNNABLE 变成 TERMINATED;
4、BLOCKED 表示线程被阻塞,如果线程正好在等待获得 monitor lock 锁,比如在等待进入 synchronized 修饰的代码块或方法时,会从 RUNNABLE 变成 BLOCKED;
5、 WAITING 和 TIMED_WAITING 都表示等待,现在在遇到 Object#wait、Thread#join、
LockSupport#park 这些方法时,线程就会等待另一个线程执行完特定的动作之后,才能结
束等待,只不过 TIMED_WAITING 是带有等待时间的;
优先级
优先级代表线程执行的机会的大小,优先级高的可能先执行,低的可能后执行。

在 Java 源码中,优先级从低到高分别是 1 到 10,线程默认 new 出来的优先级都是 5,源码如下:

/**

  • The minimum priority that a thread can have.
    */

public final static int MIN_PRIORITY = 1;

/**

  • The default priority that is assigned to a thread.
    */

public final static int NORM_PRIORITY = 5;

/**

  • The maximum priority that a thread can have.
    */

public final static int MAX_PRIORITY = 10;
线程得创建方式
我们创建多线程有两种方式,一种是继承 Thread 类,另一种是实现 Runnable 接口。两种方式的使用,如下所示:

1、继承 Thread,成为 Thread 的子类
public class MyThread extends Thread{

@Override
public void run() {
    System.out.println("我是通过继承 Thread 类实现的~");
}

public static void main(String[] args) {
    MyThread thread = new MyThread();
    // 启动线程
    thread.start();
}

}
2、实现 Runnable 接口
public class MyThread1 {

public static void main(String[] args) {
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("我是通过 runnable 方式实现的~");
        }
    });
    // 启动线程
    thread.start();
}

}
不管使用哪一种方式,启动线程都是thread.start()方法,如果你做过实验的话,你会发现 thread.run()也可以执行,为什么就一定需要调用thread.start()方法呢?

先说说结论:首先通过对象.run()方法可以执行方法,但是不是使用的多线程的方式,就是一个普通的方法,要想实现多线程的方式,一定需要通过对象.start()方法。

想要弄明白一个问题,最好的办法就是从源码入手,我们也从这两个方法的源码开始,先来看看 start 方法的源码:

public synchronized void start() {

/**
 * This method is not invoked for the main method thread or "system"
 * group threads created/set up by the VM. Any new functionality added
 * to this method in the future may have to also be added to the VM.
 *
 * A zero status value corresponds to state "NEW".
 */
 // 没有初始化,抛出异常
if (threadStatus != 0)
    throw new IllegalThreadStateException();

/* Notify the group that this thread is about to be started
 * so that it can be added to the group's list of threads
 * and the group's unstarted count can be decremented. */
group.add(this);
// 是否启动的标识符
boolean started = false;
try {
    // start0() 是启动多线程的关键
    // 这里会创建一个新的线程,是一个 native 方法
    // 执行完成之后,新的线程已经在运行了
    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 方法的源码也没几行代码,注释也比较详细,最主要的是 start0() 方法,这个后面在解释。再来看看 run() 方法的源码:

@Override
public void run() {
    // 简单的运行,不会新起线程,target 是 Runnable
    if (target != null) {
        target.run();
    }
}

run() 方法的源码就比较简单的,就是一个普通方法的调用,这也印证了我们上面的结论。

接下来我们就来说一说这个 start0() 这个方法,这个是真正实现多线程的关键,start0() 代码如下:

private native void start0();
start0 被标记成 native ,也就是本地方法,并不需要我们去实现或者了解,为什么 start0() 会标记成 native

这个要从 Java 跨平台说起,看下面这张图:

start() 方法调用 start0() 方法后,该线程并不一定会立马执行,只是将线程变成了可运行状态。具体什么时候执行,取决于 CPU ,由 CPU 统一调度。

我们又知道 Java 是跨平台的,可以在不同系统上运行,每个系统的 CPU 调度算法不一样,所以就需要做不同的处理,这件事情就只能交给 JVM 来实现了,start0() 方法自然就表标记成了 native。

最后,总结一下,Java 中实现真正的多线程是 start 中的 start0() 方法,run() 方法只是一个普通的方法。

原文地址https://www.cnblogs.com/jamaler/p/12876233.html

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
java类模拟客户端调用servlet (httpClient)
java类模拟客户端调用servlet (httpClient)
58 0
java类模拟客户端调用servlet (httpClient)
最近做项目,用到JAVA普通类调用一个servlet应用,所以把部分代码也贴上来了。
57 0
IDEA+Java+JSP+Mysql+Tomcat实现Web图书管理系统(上)
IDEA+Java+JSP+Mysql+Tomcat实现Web图书管理系统
88 0
IDEA+Java+JSP+Mysql+Tomcat实现Web图书管理系统(下)
IDEA+Java+JSP+Mysql+Tomcat实现Web图书管理系统
61 0
IDEA+Java+JSP+Mysql+Tomcat实现Web图书管理系统-添加管理员增删改查功能(上)
IDEA+Java+JSP+Mysql+Tomcat实现Web图书管理系统-添加管理员增删改查功能
158 0
IDEA+Java+JSP+Mysql+Tomcat实现Web图书管理系统-添加管理员增删改查功能(下)
IDEA+Java+JSP+Mysql+Tomcat实现Web图书管理系统-添加管理员增删改查功能
101 0
Java实现生产者消费者的四种方法
Java生产者和消费者问题是线程安全模型中的经典问题:生产者和消费者在同一个时间段共用同一个存储空间,生产者向存储空间中添加产品呢,消费者取走产品,当存储空间为空时,消费者阻塞,当存储空间满时,生产者阻塞
149 0
Java实现小型酒店管理系统。
编写Java程序实现小型酒店管理系统。
77 0
java从入门到精通四(面向对象上,类与对象的实现,代码块的执行顺序)
一 :面向对象的概念 面向对象的方法主要是把事物对象化,包括属性和行为。而面向对象编程则比较贴近生活的实际,也就说,在程序中的编程,力图对描述的事物在现实中的形态保持一致。为了做到这一点,我们java中也就有类和对象的概念。类是对一类事物的抽象,类下就有若干对象,对象用于描述类中事物的个体。说来光看定义还是比较抽象,不容易理解。我们在下面的编程实践中可以大致理解这种思维模式。
29 0
Java实现雪景图
Java实现雪景图-Java项目实践学习-涉及Jframe/Jpanel等
32 0
+关注
推荐码发放
阿里云优惠码阿里云推荐券bieryun.com
文章
问答
文章排行榜
最热
最新
相关电子书
更多
JAVA反射原理以及一些常见的应用
立即下载
Java基础入门(四)-泛型、反射、注解
立即下载
The state of SQL-on-Hadoop in the Cloud
立即下载