• 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
  • 相关阅读:
    利用nginx实现负载均衡和动静分离
    Nginx动静分离实现
    php中session 入库的实现
    php文字水印和php图片水印实现代码(二种加水印方法)
    采集图片水印添加
    [安全]PHP能引起安全的函数
    [安全]服务器安全之 PHP权限目录
    Centos下安装git的web服务器
    Centos下抓包
    UVA 10795
  • 原文地址:https://www.cnblogs.com/L-Test/p/12112480.html
Copyright © 2020-2023  润新知