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

发表于:2020-5-12 09:41

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:互联网平头哥    来源:互联网平头哥

#
java
#
Java
  多线程在工作中多多少少会用到,启动多线程调用的是 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() 方法后,该线程并不一定会立马执行,只是将线程变成了可运行状态(NEW ---> RUNNABLE)。具体什么时候执行,取决于 CPU ,由 CPU 统一调度。
  我们又知道 Java 是跨平台的,可以在不同系统上运行,每个系统的 CPU 调度算法不一样,所以就需要做不同的处理,这件事情就只能交给 JVM 来实现了,start0() 方法自然就表标记成了 native。
  最后,总结一下,Java 中实现真正的多线程是 start 中的 start0() 方法,run() 方法只是一个普通的方法。

      本文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号