详细探究Java多线程的线程状态变化

简介: Java多线程的线程状态主要有六种:新建(NEW)、可运行(RUNNABLE)、阻塞(BLOCKED)、等待(WAITING)、超时等待(TIMED_WAITING)和终止(TERMINATED)。线程创建后处于NEW状态,调用start()后进入RUNNABLE状态,表示准备好运行。当线程获得CPU资源,开始执行run()方法时,它处于运行状态。线程可以因等待锁或调用sleep()等方法进入BLOCKED或等待状态。线程完成任务或发生异常后,会进入TERMINATED状态。

2.1 线程状态

当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,有几种状态呢?在API中java.lang.Thread.State这个枚举中给出了六种线程状态:

这里先列出各个线程状态发生的条件,下面将会对每种状态进行详细解析;

线程状态

导致状态发生条件

New(新建)

线程刚被创建,但是并未启动。还没调用start方法。

Runnable(可运行)

线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。

Blocked(锁阻塞)

当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。

Waiting(无限等待)

一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。

Timed Waiting(计时等待)

同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait。

Teminated(被终止)

因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

2.1.1 New

  • New:新建状态

表示线程被创建但尚未启动的状态:当我们用 new Thread() 新建一个线程时,如果线程没有开始运行 start() 方法,那么线程也就没有开始执行 run() 方法里面的代码,那么此时它的状态就是 New。而一旦线程调用了 start(),它的状态就会从 New 变成 Runnable

【示例代码】

package com.dfbz.demo01_线程的状态;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo01_线程状态_NEW {
    public static void main(String[] args) {
        Thread t1 = new Thread(){
            @Override
            public void run() {
            }
        };
        // 线程未启动之前的状态都是NEW
        System.out.println(t1.getState());          // NEW
    }
}

2.1.2 Runnable

  • Runnable:可运行状态

一旦线程调用start()方法,线程就处于可运行状态(Runnable)。

一个可运行的线程能正在运行可能没有运行。有些教科书上讲可运行状态分为了就绪状态运行状态,即线程开启后进入就绪状态,当线程抢到CPU执行权后进入运行状态(Java规范没有将正在运行作为一个单独的状态,一个正在运行的线程仍然处于可运行状态)

【示例代码】

package com.dfbz.demo01_线程的状态;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo02_线程状态_RUNNABLE {
    public static void main(String[] args) {
        Thread t1 = new Thread(){
            @Override
            public void run() {
                while (true){
                }
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run() {
                while (true){
                }
            }
        };
        t1.start();
        t2.start();
        // 线程只要开启之后不管是否处于运行状态
        System.out.println(t1.getState());          // RUNNABLE
        System.out.println(t2.getState());          // RUNNABLE
    }
}

2.1.3 Blocked

  • Blocked:锁阻塞状态(在IDEA断点显示的MONITOR状态)

Blocked从 Runnable 状态进入到 Blocked 状态只有一种途径,那么就是当进入到 synchronized 代码块中时未能获得相应的锁,当有线程从 Blocked 状态指向了 Runnable ,也只有一种情况,那么就是当线程获得锁,此时线程就会进入 Runnable 状体中参与 CPU 资源的抢夺

【示例代码】

package com.dfbz.demo01_线程的状态;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo03_线程状态_BLOCKED {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread() {
            @Override
            public void run() {
                synchronized (Object.class) {
                    while (true) {
                    }
                }
            }
        };
        Thread t2 = new Thread() {
            @Override
            public void run() {
                // t2线程获取不到锁,被锁阻塞在外面
                synchronized (Object.class) {
                }
            }
        };
        t1.start();
        // 过一会再开启线程2(确保线程1必定先获取CPU执行权)
        Thread.sleep(10);
        t2.start();
        System.out.println(t1.getState());          // RUNNABLE
        System.out.println(t2.getState());          // BLOCKED
    }
}

2.1.4 Timed Waiting

Timed Waiting 状态,它与 Waiting 状态非常相似,其中的区别只在于是否有时间的限制,在 Timed Waiting 状态时会等待超时,之后由系统唤醒

在以下情况会让线程进入 Timed Waiting 状态。

  • 线程执行了设置了时间参数的 Thread.sleep(long millis) 方法;
  • 线程执行了设置了时间参数的 Object.wait(long timeout) 方法;
  • 线程执行了设置了时间参数的 Thread.join(long millis) 方法;

通过这个我们可以进一步看到它与 waiting 状态的相同

【示例代码1-sleep】:

package com.dfbz.demo01_线程的状态;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo04_线程状态_TIMED_WAITING_01_sleep {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t1.start();
        // 让main线程睡眠一段时间(确保t1线程能够执行)
        Thread.sleep(100);
        System.out.println(t1.getState());          // TIMED_WAITING
    }
}

【示例代码2-wait】

package com.dfbz.demo01_线程的状态;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo05_线程状态_TIMED_WAITING_02_wait {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread() {
            @Override
            public void run() {
                synchronized (Object.class) {
                    while (true) {
                        try {
                            Object.class.wait(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        };
        t1.start();
        // 让main线程睡眠一段时间(确保t1线程能够执行)
        Thread.sleep(100);
        System.out.println(t1.getState());          // TIMED_WAITING
    }
}

【示例代码3-join】

package com.dfbz.demo01_线程的状态;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo06_线程状态_TIMED_WAITING_03_join {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread() {
            @Override
            public void run() {
                while (true) {
                }
            }
        };
        Thread t2 = new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        // 让t1线程先执行10s,t2将处于TIMED_WAITING状态
                        t1.join(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t1.start();
        t2.start();
        // 让main线程睡眠1s,保证t1线程能执行join方法
        Thread.sleep(1000);
        System.out.println(t1.getState());          // RUNNABLE
        System.out.println(t2.getState());          // TIMED_WAITING
    }
}

2.1.5 Waiting

对于 Waiting 状态的进入有3种情况,分别为:

  • 1)当线程中调用了没有设置 Timeout 参数的 Object.wait() 方法
  • 2)当线程调用了没有设置 Timeout 参数的 Thread.join() 方法
  • 3)当线程调用了 LockSupport.park() 方法

【示例代码1-wait】:

package com.dfbz.demo01_线程的状态;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo07_线程状态_WAITING_01_wait {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread() {
            @Override
            public void run() {
                synchronized (Object.class) {
                    try {
                        Object.class.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t1.start();
        // 让当前线程睡眠0.1s,确保t1线程能够执行wait
        Thread.sleep(100);
        System.out.println(t1.getState());          // WAITING
    }
}

【示例代码2-join】:

package com.dfbz.demo01_线程的状态;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo08_线程状态_WAITING_02_join {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread() {
            @Override
            public void run() {
                while (true){
                }
            }
        };
        Thread t2 = new Thread() {
            @Override
            public void run() {
                try {
                    t1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t1.start();
        t2.start();
        // 让当前线程睡眠0.1s,确保t1线程能够执行join
        Thread.sleep(100);
        System.out.println(t1.getState());          // RUNNABLE
        System.out.println(t2.getState());          // WAITING
    }
}

【示例代码3-park】:

package com.dfbz.demo01_线程的状态;
import java.util.concurrent.locks.LockSupport;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo09_线程状态_WAITING_03_park {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread() {
            @Override
            public void run() {
                while (true){
                    LockSupport.park();
                }
            }
        };
        t1.start();
        // 让当前线程睡眠0.1s,确保t1线程能够执行park
        Thread.sleep(100);
        System.out.println(t1.getState());          // WAITING
    }
}

Blocked与Waiting的区别:

  • Blocked 是在等待其他线程释放锁
  • Waiting 则是在等待某个条件,比如 join 的线程执行完毕,或者是 notify()/notifyAll() 。

2.1.6 Terminated

Terminated:终止状态,要想进入Terminated 状态有两种可能。

  • 1)run() 方法执行完毕,线程正常退出。
  • 2)出现一个没有捕获的异常,终止了 run() 方法,最终导致意外终止。

【示例代码】:

package com.dfbz.demo01_线程的状态;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo10_线程状态_TERMINATED {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread() {
            @Override
            public void run() {
                System.out.println("t1 running...");
            }
        };
        t1.start();
        // 让当前线程睡眠10毫秒,确保t1线程任务执行完毕
        Thread.sleep(10);
        System.out.println(t1.getState());          // TERMINATED
    }
}

2.2 线程状态变化

线程流程图:

接下来我们将来分析各自状态之间的转换,其实主要就是 Blocked、waiting、Timed Waiting 三种状态的转换 ,以及他们是如何进入下一状态最终进入 Runnable

2.2.1  Runnable与Blocked状态转换

  • 1)Runnable状态进入Blocked状态:当前线程竞争锁对象失败时:Runnable-->Blocked
  • 2)Blocked状态进入Runnable状态:当之前的线程释放了锁对象时,新的线程竞争到了锁对象时:Blocked-->Runnable

【示例代码】:

package com.dfbz.demo02_线程状态的改变;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo01_Runnable进入Blocked状态 {
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        Thread t1 = new Thread(() -> {
            while (true) {
                synchronized (obj) {
                    System.out.println("t1");
                }
            }
        }, "t1");
        Thread t2 = new Thread(() -> {
            while (true) {
                synchronized (obj) {
                    System.out.println("t2");
                }
            }
        }, "t2");
        t1.start();
        t2.start();
    }
}

Tips:断点记得使用Thread模式;

2.2.2  Runnable与Waiting状态转换

Runnable状态与Waiting状态有三种情况,分别为wait、join、park;

1) Runnable转Waiting

Runnable状态进入Waiting状态:

  • 1)调用wait方法
  • 2)调用join方法
  • 3)调用park方法

【示例代码-01-wait】

package com.dfbz.demo02_线程状态的改变;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo02_Runnable进入Waiting状态_01_wait {
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        Thread t1 = new Thread(() -> {
            synchronized (obj) {
                System.out.println("t1-before..");
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t1-after..");
            }
        }, "t1");
        t1.start();
        // 确保t1线程先执行
        Thread.sleep(10);
        new Thread(() -> {
            synchronized (obj) {
                // 将所有线程都唤醒,唤醒的线程都将处于blocked状态,因为要等当前线程释放锁对象
                obj.notifyAll();
            }
        },"t2").start();
    }
}

分析:

【示例代码-02-join】

package com.dfbz.demo02_线程状态的改变;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo02_Runnable进入Waiting状态_02_join {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                while (true){
                }
            }
        };
        Thread t2 = new Thread("t2") {
            @Override
            public void run() {
                System.out.println("t2-before...");
                try {
                    t1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t2-after...");
            }
        };
        t1.start();
        t2.start();
        // 让当前线程睡眠10ms,确保t1线程能够执行join
        Thread.sleep(10);
        System.out.println(t1.getState());          // RUNNABLE
        System.out.println(t2.getState());          // WAITING
    }
}

【示例代码-03-park】

package com.dfbz.demo02_线程状态的改变;
import java.util.concurrent.locks.LockSupport;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo03_Runnable进入Waiting状态_03_park {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                while (true){
                    System.out.println("t1-before");
                    System.out.println(Thread.currentThread().getState());
                    LockSupport.park();
                    System.out.println(Thread.currentThread().getState());
                    System.out.println("t1-after");
                }
            }
        };
        t1.start();
        // 确保t1线程先执行
        Thread.sleep(10);
        System.out.println(t1.getState());          // 使用断点让park方法先执行,此时线程状态为Waiting
    }
}

2) Waiting转Runnable

Waiting状态进入Runnable状态:

  • 1)wait:
  • 1)notifly或notifyAll方法(需要注意的是先进入Blocked再进入Runnable)进入Runnable状态
  • 2)使用interrupt()中断线程(中断状态为false)
  • 2)join:
  • 1)等待join线程执行完毕
  • 2)使用interrupt()中断线程(中断状态为false)
  • 3)park:
  • 1)调用unpark方法
  • 2)使用interrupt()中断线程(并不会出现InterruptException,而且中断状态为true,相当于直接唤醒)

【示例代码Waiting转Runnable-01-wait-notify】

需要注意的是:如果一个线程处于 Waiting 状态,其他线程调用 notify() 或 notifyAll()来唤醒它,则它会直接进入 **Blocked** 状态,这里可能会有疑问,不是应该直接进入 Runnable 吗?

这里需要注意一点 ,如果调用 notify() 或 notifyAll(),要求该现场必须首先持有该锁,锁已经被该线程获取了,被唤醒的线程自然就获取不到锁,处于Blocked状态;直到执行了 notify()/notifyAll() 的线程执行完毕并释放锁,被唤醒的线程才可能轮到它去抢夺这把锁,如果它能抢到,就会从 Blocked 状态回到 Runnable 状态。

package com.dfbz.demo02_线程状态的改变;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo04_Waiting进入Runnable状态_01_wait_notify {
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        Thread t1 = new Thread(() -> {
            synchronized (obj) {
                System.out.println("t1-before..");
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t1-after..");
            }
        }, "t1");
        t1.start();
        // 确保t1线程先执行
        Thread.sleep(10);
        new Thread(() -> {
            synchronized (obj) {
                // 将所有线程都唤醒,唤醒的线程都将处于blocked状态,因为要等当前线程释放锁对象
                obj.notifyAll();
            }
        },"t2").start();
    }
}

当我们通过 notify 唤醒线程时,被唤醒的线程是先进入锁阻塞状态的 ,再等抢夺到锁后才会进入 Runnable 状态

【示例代码Waiting转Runnable-02-wait-interrupt】

package com.dfbz.demo02_线程状态的改变;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo05_Waiting进入Runnable状态_02_wait_interrupt {
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        Thread t1 = new Thread(() -> {
            synchronized (obj) {
                System.out.println("t1-before..");
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t1-after..");
            }
        }, "t1");
        t1.start();
        // 确保t1线程先执行
        Thread.sleep(10);
        t1.interrupt();
    }
}

【示例代码Waiting转Runnable-03-join-join任务执行结束】

package com.dfbz.demo02_线程状态的改变;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo06_Waiting进入Runnable状态_03_join {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                // ③执行t1线程的run方法(将方法执行完毕)
                System.out.println("t1...");
            }
        };
        // ①首先t1开启线程(此时t1处于可运行状态)
        t1.start();
        // ②让t1线程执行join方法,此时main处于等待状态
        t1.join();
        // ④再次回到main方法,main从等待转换变为了可运行状态
        System.out.println("main");
    }
}

【示例代码Waiting转Runnable-04-join-interrupt】

package com.dfbz.demo02_线程状态的改变;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo07_Waiting进入Runnable状态_04_join_interrupt {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                System.out.println("t1...");
            }
        };
        Thread t2 = new Thread("t2") {
            @Override
            public void run() {
                System.out.println("t2-before...");
                try {
                    // ②让t1执行join方法,此时t2处于等待状态
                    t1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t2-after...");
            }
        };
        // ①首先开启两个线程
        t1.start();
        t2.start();
        // ③t2执行interrupt方法,t2从等待状态变为可运行状态
        t2.interrupt();
    }
}

【示例代码Waiting转Runnable-05-wait-notify】

package com.dfbz.demo02_线程状态的改变;
import java.util.concurrent.locks.LockSupport;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo08_Waiting进入Runnable状态_05_park_unpark {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                while (true){
                    System.out.println("t1-before");
                    // ②让t1线程执行park(此时处于等待状态)
                    LockSupport.park();
                    System.out.println("t1-after");
                }
            }
        };
        // ①启动t1线程
        t1.start();
        // ③执行unpark方法,此时t1处于可运行状态
        LockSupport.unpark(t1);
        System.out.println("main end...");
    }
}

【示例代码Waiting转Runnable-06-wait-notify】

package com.dfbz.demo02_线程状态的改变;
import java.util.concurrent.locks.LockSupport;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo09_Waiting进入Runnable状态_06_park_interrupt {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                while (true){
                    System.out.println("t1-before");
                    // ②让t1线程执行park(此时处于等待状态)
                    LockSupport.park();
                    System.out.println("t1-after");
                }
            }
        };
        // ①启动t1线程
        t1.start();
        // ③执行interrupt方法,相当于唤醒t1线程,此时t1线程为可运行状态
        t1.interrupt();
        System.out.println("main end...");
    }
}

2.2.3  Runnable与Timed Waiting状态转换

1) Runnable转Timed Waiting

Runnable进入Timed Waiting:

  • 1)线程执行了设置了时间参数的 Thread.sleep(long millis) 方法;
  • 2)线程执行了设置了时间参数的 Object.wait(long timeout) 方法;
  • 3)线程执行了设置了时间参数的 Thread.join(long millis) 方法;

2) Timed Waiting转Runnable

  • 1)Thread.sleep(long millis) :
  • 1)等到millis时间到达
  • 2)使用interrupt中断线程(中断状态还是false)
  • 2)Object.wait(long timeout):
  • 1)等到timeout时间到达
  • 2)使用interrupt中断线程(中断状态还是false)
  • 3)使用notifly或notiflyAll唤醒(首先进入Blocked状态,竞争到锁之后再进入Runnable状态)
  • 3)Thread.join(long millis):
  • 1)等到timeout时间到达
  • 2)使用interrupt中断线程(中断状态还是false)
  • 3)使用notifly或notiflyAll唤醒(首先进入Blocked状态,竞争到锁之后再进入Runnable状态)
Tips:notifly和notiflyAll只能唤醒使用wait方法进行等待的线程;

【示例代码1】:

1)测试sleep方法时间到达后线程状态从Timed Waiting变为Runnable

2)测试调用interrupt()方法将线程状态从Timed Waiting变为Runnable

package com.dfbz.demo02_线程状态的改变;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo10_Runnable与TimedWaiting状态_01_sleep {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                System.out.println("t1-before...");
                try {
                    // ②线程睡眠(从可运行变为了计时等待),当睡眠时间结束后自动从计时等待变为可运行状态
                    Thread.sleep(1000000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t1-after...");
            }
        };
        // ①开启线程
        t1.start();
        // ③调用interrupt中断计时等待状态的线程,t1从计时等待变为了可运行状态
        t1.interrupt();
    }
}

分析:

【示例代码2-1】:

1)测试wait方法时间到达后线程状态从Timed Waiting变为Runnable

2)测试调用interrupt()方法将线程状态从Timed Waiting变为Runnable

package com.dfbz.demo02_线程状态的改变;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo03_Runnable与TimedWaiting状态_02_wait方法 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                synchronized (Object.class){
                    System.out.println("t1-before...");
                    try {
                        // 等到wait的时间到达之后线程自动从Timed Waiting状态变为Runnable状态
                        Object.class.wait(30000000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("t1-after...");
                }
            }
        };
        t1.start();
        // 确保t1线程先执行
        Thread.sleep(10);
        // 中断之前t1的状态为Timed Waiting,中断之后t1的状态为Runnable
        t1.interrupt();
    }
}

需要注意的是,在IDEA中,只要调用wait方法,那么IDEA在调试窗口中就会线程该线程为WAIT,但此时这个线程是计时等待状态,我们可以通过右键菜单--->Evaluate Expression...,查看t1的状态:

【示例代码2-2】:使用notify/notiflyAll将线程状态从Timed Waiting变为Runnable(Blocked)

package com.dfbz.demo02_线程状态的改变;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo12_Runnable与TimedWaiting状态_03_wait_notify {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                synchronized (Object.class){
                    System.out.println("t1-before...");
                    try {
                        // ②执行wait方法(从可运行变为了计时等待),如果时间结束,那么线程自动进入可运行状态
                        // 注意: 调用wait方法会释放锁
                        Object.class.wait(30000000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("t1-after...");
                }
            }
        };
        // ①开启线程
        t1.start();
        synchronized (Object.class){
            // ③执行notify方法,把t1唤醒,t1从计时等待变为了锁阻塞状态
            // 唤醒之前t1的状态为Timed Waiting,唤醒之后t1的状态为Blocked,等到t1线程获取到锁之后状态为Runnable
            Object.class.notify();
        }
    }
}

【示例代码3】:

1)测试join方法时间到达后线程状态从Timed Waiting变为Runnable

2)测试调用interrupt()方法将线程状态从Timed Waiting变为Runnable

package com.dfbz.demo02_线程状态的改变;
/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo13_Runnable与TimedWaiting状态_04_join {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                while (true){}
            }
        };
        Thread t2 = new Thread("t2") {
            @Override
            public void run() {
                try {
                    // ②执行join方法(t2从可运行变为了计时等待),如果时间结束,那么线程自动进入可运行状态
                    t1.join(3000000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t2-after..");
            }
        };
        // ①开启t1、t2线程
        t1.start();
        t2.start();
        // ③调用interrupt中断计时等待状态的线程(中断状态为false),t2从计时等待变为了可运行状态
        t2.interrupt();
    }
}

2.2.2 状态变化的注意事项

  • 1)线程从 New 状态是不可以直接进入 Blocked 状态的,它需要先经历 Runnable 状态。
  • 2)线程生命周期不可逆,一旦进入 Runnable 状态就不能回到 New 状态;一旦被终止就不可能再有任何状态的变化。
  • 3)所以一个线程只能有一次 New 和 Terminated 状态,只有处于中间状态才可以相互转换。也就是这两个状态不会参与相互转化
相关文章
|
16天前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
72 17
|
26天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
12天前
|
缓存 安全 算法
Java 多线程 面试题
Java 多线程 相关基础面试题
|
28天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
28天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。
|
29天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
55 3
|
29天前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
157 2
|
29天前
|
NoSQL Redis
单线程传奇Redis,为何引入多线程?
Redis 4.0 引入多线程支持,主要用于后台对象删除、处理阻塞命令和网络 I/O 等操作,以提高并发性和性能。尽管如此,Redis 仍保留单线程执行模型处理客户端请求,确保高效性和简单性。多线程仅用于优化后台任务,如异步删除过期对象和分担读写操作,从而提升整体性能。
62 1
|
1月前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
52 6
|
1月前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####