Java并发02:开启多线程启动的世界

547 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情

学习MOOC视频记录的笔记

启动线程的正确和错误方式

1.start()run() 的比较

 public class StartAndRunMethod {
     public static void main(String[] args) {
         Runnable runnable = () -> {
             System.out.println(Thread.currentThread().getName());
         };
         // main
         runnable.run();
  
         // Thread-0
         new Thread(runnable).start();
     }
 }

2.start()方法原理解读

调用 start() 方法的顺序并不能决定线程执行的顺序

start() 方法含义

  • 启动新线程

    • 调用 start 方法实际上只是告诉 JVM 你合适的时候来启动新线程 【请求 JVM 来运行这个线程,线程究竟何时运行是由线程调度器去决定的】
    • 会同时让两个线程运行,即 main 主线程和子线程,new Thread().start()是由主线程执行的,执行完成之后才创建的子线程。
  • 准备工作

    (新线程)让自己处于就绪状态,已经获取了除了CPU之外的其他资源,已经设置了栈,上下文状态,PC等,只等获取CPU资源就可以进入运行状态执行run方法中的代码。

  • 不能重复执行 start 方法

 /**
 * 不能两次调用start方法,否则会报错
 */
 public class CantStartTwice {
     public static void main(String[] args) {
         Thread thread = new Thread();
         thread.start();
         thread.start();
     }
 }
 Exception in thread "main" java.lang.IllegalThreadStateException
     at java.lang.Thread.start(Thread.java:708)
     at threadcoreknowledge.startthread.CantStartTwice.main(CantStartTwice.java:12)

报错提示为非法的线程状态,表示一旦开始执行线程状态就从最开始的New状态进入到后续的状态,一旦线程执行完毕就进入终止状态,终止状态永远无法返回回去。

start()源码解析

  • 启动新线程检查线程状态
  • 加入线程组
  • 调用 start0()
 public synchronized void start() {
  
     // 检查是不是刚初始化还没有启动的状态
     if (threadStatus != 0)
         throw new IllegalThreadStateException();
         // 加入线程组
         group.add(this);
  
         boolean started = false;
         try {
             // native 方法,代码由C/C++实现的
             start0();
             started = true;
         } finally {
             try {
                 if (!started) {
                     group.threadStartFailed(this);
                 }
             } catch (Throwable ignore) {
  
             }
         }
 }
 /* Java thread status for tools,
 * initialized to indicate thread 'not yet started'
 */
  
 // Java线程状态初始值为0,表示还未启动
 private volatile int threadStatus = 0;

3.run() 方法原理解读

  • 源码解析
  • 两种情况
 @Override
 public void run() {
     if (target != null) {
         target.run();
     }
 }

4.彩蛋:Java 名字的由来

  • OakLyric
  • CAFE BABE class文件16进制文件头
  • Beans

启动线程———常见面试题问题

  • 一个线程两次调用 start() 方法会出现什么情况?为什么?
  1. 会抛出异常
  2. 由于线程会检查 threadStatus 如果不符合(已经执行了 start() 方法)
  3. 引申线程状态问题
  • 既然 start() 方法会调用 run() 方法,为什么我们选择调用 start 方法,而不是直接调用 run() 方法呢?

因为调用 start() 方法才是真正意义上启动了一个线程,它会经历线程的各个生命周期,而直接调用 run() 方法它就是一个普通的方法而已,也不会用子线程调用。