• Java学习之==> Java线程生命周期与状态切换


    一、Java线程生命周期与状态切换

    这些状态的描述可以总结成下图:

    NEW

    一个刚创建但尚未启动的Java线程实例就是处于 NEW 状态

    public class App {
    
      public static void main(String[] args) {
    
        Thread thread = new Thread();
    
        Thread.State state = thread.getState();
    
        System.out.println(state);
      }
    }
    
    // 输出结果
    NEW

    RUNNABLE

    当Java线程实例调用了 Thread.start() 方法后,就会进入 RUNNABLE 状态,RUNNABLE状态包含两个子状态:READY 和 RUNNING。

    • READY:该状态的线程可以被线程调度器进行调度使之更变为RUNNING状态。
    • RUNNING:该状态表示线程正在运行,线程对象的run()方法中的代码所对应的的指令正在被CPU执行。

    当Java线程实例Thread.yield()方法被调用时或者由于线程调度器的调度,线程实例的状态有可能由RUNNING转变为READY,但是从线程状态Thread.getState()获取到的状态依然是RUNNABLE。例如:

    public class App {
    
      public static void main(String[] args) {
    
        Thread thread = new Thread(()->{
    
          Thread.yield();
    
          System.out.println("testThreadState");
        });
    
        thread.start();
    
        Thread.State state = thread.getState();
    
        System.out.println(state);
      }
    }
    
    // 输出结果
    RUNNABLE
    testThreadState

    BLOCKED

    阻塞状态,该状态下的线程不会被CPU分配执行时间,线程的状态为 BLOCKED的时候有两种可能的情况:

    • 线程正在等待一个监视器锁,只有获取监视器锁之后才能进入synchronized代码块或者synchronized方法,在此等待获取锁的过程线程都处于阻塞状态。
    • 线程 X 已步入synchronized代码块或者synchronized方法后,调用Object.wait()方法之后进行阻塞(此时已经释放监视器锁),然后线程 T 获取到该监视器锁,此时,如果线程 X 接收到线程 T 调用该锁对象Object#notify()/notifyAll(),但是线程 T 尚未退出它所在的synchronized代码块或者synchronized方法,那么线程 X 依然处于阻塞状态(注意API注释中的reenter,理解它场景2就豁然开朗)。 
    public class App {
    
      public static void main(String[] args) {
        App app = new App();
    
        Thread thread1 = new Thread(() -> {
          app.produce();
        });
    
        Thread thread2 = new Thread(() -> {
          app.consumer();
        });
    
        thread1.start();
        thread2.start();
        System.out.println("thread1:" + thread1.getState());
        System.out.println("thread2:" + thread2.getState());
      }
    
      public void produce() {
        synchronized (this) {
          try {
            Thread.sleep(5000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    
      public void consumer() {
        synchronized (this) {
          System.out.println("testThread");
        }
      }
    }
    
    // 输出结果
    thread1:RUNNABLE
    thread2:BLOCKED
    testThread
    第一种情况

    thread1先运行,拿到 synchronized 锁,执行 produce方法中的 synchronized 代码块中的代码-->等待5秒,这时候 thread2 再运行,状态为 BLOCKED,等到 thread1执行 synchronized代码块结束,thread2 拿到 synchronized 锁,才能执行 consume 方法中的 synchronized 代码块中的代码。

    public class App {
    
      public static void main(String[] args) throws InterruptedException {
        App app = new App();
    
        Thread thread1 = new Thread(() -> {
          app.produce();
        });
    
        Thread thread2 = new Thread(() -> {
          app.consumer();
        });
    
        thread1.start();
        thread2.start();
        // 这里让主线程sleep 1500毫秒从而让thread2调用了notify()并且尚未退出synchronized代码块,确保thread1执行了wait()
        Thread.sleep(1500);
        System.out.println("thread1:" + thread1.getState());
        System.out.println("thread2:" + thread2.getState());
      }
    
      public void produce() {
        synchronized (this) {
          try {
            this.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    
      public void consumer() {
        synchronized (this) {
          try {
            this.notify();
            Thread.sleep(3000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          System.out.println("testThread");
        }
      }
    }
    
    // 输出结果
    thread1:BLOCKED
    thread2:TIMED_WAITING
    testThread
    第二种情况

    thread1先运行,执行 wait() 方法进入 WAITING状态并释放锁,thread2再执行,执行 notify()方法唤醒 thread1,本来 thread1应该变化为 RUNNABLE状态,但是因为 thread2的synchronized代码块还没执行完,后面还有一个 Thread.sleep(3000)没执行完,thread2还拿着这把锁,所以,thread1就还是BLOCKED阻塞状态。

    WAITING

    无限期的等待状态,这种状态下的线程不会被CPU分配执行时间。当一个线程执行了某些方法后就会进入 WAITING 状态,被显式唤醒后又变化为 RUNNABLE状态继续执行。

    RUNNABLE 转换为 WAITING 的方法:

    • Object#wait()
    • Thread#join()
    • LockSupport.park()

    WAITING 转换为 RUNNABLE 的方法:

    • Object#notify()或者Object#notifyAll()
    • LockSupport.unpark(thread)
    public class App {
    
      public static void main(String[] args) throws InterruptedException {
        App app = new App();
    
        Thread thread = new Thread(() -> {
          app.produce();
        });
    
        thread.start();
        // 这里让主线程sleep 1500毫秒,确保thread执行了wait()
        Thread.sleep(1500);
        System.out.println("thread:" + thread.getState());
      }
    
      public void produce() {
        synchronized (this) {
          try {
            this.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    }
    
    // 输出结果
    thread:WAITING

    TIMED_WAITING

    有限期等待状态,它和WAITING有点相似,这种状态下的线程不会被分配CPU执行时间,不过这种状态下的线程不需要被显式唤醒,只需要等待超时限期到达就会被唤醒。 

    RUNNABLE转换为TIMED_WAITING的方法:

    • Object#wait(timeout)
    • Thread#sleep(timeout)
    • Thread#join(timeout)
    • LockSupport.parkNanos(timeout)
    • LockSupport.parkUntil(timeout)

    待超时时间结束,就由TIMED_WAITING状态转换为RUNNABLE状态。

    public class App {
    
      public static void main(String[] args) throws InterruptedException {
        App app = new App();
    
        Thread thread = new Thread(() -> {
          app.produce();
        });
    
        thread.start();
        // 这里让主线程sleep 50毫秒,确保thread执行了Thread.sleep(3000)
        Thread.sleep(50);
        System.out.println("thread:" + thread.getState());
      }
    
      public void produce() {
        synchronized (this) {
          try {
            Thread.sleep(3000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    }
    
    // 输出结果
    thread:TIMED_WAITING

    TERMINATED

    TERMINATED状态表示线程已经终结。一个线程实例只能被启动一次,准确来说,只会调用一次Thread#run()方法,Thread#run()方法执行结束之后,线程状态就会更变为TERMINATED,意味着线程的生命周期已经结束。

    public class App {
    
      public static void main(String[] args) throws InterruptedException {
        App app = new App();
    
        Thread thread = new Thread(() -> {
          app.produce();
        });
    
        thread.start();
        // 这里让主线程sleep 50毫秒,确保thread执行了synchronized代码块中的代码
        Thread.sleep(50);
        System.out.println("thread:" + thread.getState());
      }
    
      public void produce() {
        synchronized (this) {
          System.out.println("testThread");
        }
      }
    }
    // 输出结果
    testThread
    thread:TERMINATED
  • 相关阅读:
    Java学习开篇
    《我的姐姐》
    世上本无事,庸人自扰之
    这48小时
    补觉
    淡定
    es java api 设置index mapping 报错 mapping source must be pairs of fieldnames and properties definition.
    java mongodb groupby分组查询
    linux 常用命令
    mongodb too many users are authenticated
  • 原文地址:https://www.cnblogs.com/L-Test/p/12112480.html
Copyright © 2020-2023  润新知