线程的状态,wait和sleep——Java全栈知识(39)

线程的状态

1、线程的状态

我们可以看到线程的状态可以参考 JDK 中的 Thread 类中的枚举 State

public enum State {
        /**
         * 尚未启动的线程的线程状态
         */
        NEW,

        /**
         * 可运行线程的线程状态。处于可运行状态的线程正在 Java 虚拟机中执行,但它可能正在等待来自		 * 操作系统的其他资源,例如处理器。
         */
        RUNNABLE,

        /**
         * 线程阻塞等待监视器锁的线程状态。处于阻塞状态的线程正在等待监视器锁进入同步块/方法或在调          * 用Object.wait后重新进入同步块/方法。
         */
        BLOCKED,

        /**
         * 等待线程的线程状态。由于调用以下方法之一,线程处于等待状态:
		* Object.wait没有超时
         * 没有超时的Thread.join
         * LockSupport.park
         * 处于等待状态的线程正在等待另一个线程执行特定操作。
         * 例如,一个对对象调用Object.wait()的线程正在等待另一个线程对该对象调用Object.notify()			* 或Object.notifyAll() 。已调用Thread.join()的线程正在等待指定线程终止。
         */
        WAITING,

        /**
         * 具有指定等待时间的等待线程的线程状态。由于以指定的正等待时间调用以下方法之一,线程处于定          * 时等待状态:
		* Thread.sleep
		* Object.wait超时
		* Thread.join超时
		* LockSupport.parkNanos
		* LockSupport.parkUntil
         * </ul>
         */
        TIMED_WAITING,

        /**
         * 已终止线程的线程状态。线程已完成执行
         */
        TERMINATED;
    }

所以说 Java 中线程可以分为以下几种状态:
1、NEW(新建)

  • 当一个线程对象被创建,但还未调用 start 方法时处于新建状态
  • 此时未与操作系统底层线程关联
    2、RUNNABLE(可运行)
  • 调用了 start 方法,就会由新建进入可运行
  • 此时与底层线程关联,由操作系统调度执行
    3、BLOCKED(阻塞)
  • 当获取锁失败后,由可运行进入 Monitor 的阻塞队列阻塞,此时不占用 cpu 时间
  • 当持锁线程释放锁时,会按照一定规则唤醒阻塞队列中的阻塞线程,唤醒后的线程进入可运行状态
    4、WAITING(等待)
  • 当获取锁成功后,但由于条件不满足,调用了 wait() 方法,此时从可运行状态释放锁进入 Monitor 等待集合等待,同样不占用 cpu 时间
  • 当其它持锁线程调用 notify() 或 notifyAll() 方法,会按照一定规则唤醒等待集合中的等待线程,恢复为可运行状态
    5、TIMED_WAITING(有时限等待)
  • 当获取锁成功后,但由于条件不满足,调用了 wait(long) 方法,此时从可运行状态释放锁进入 Monitor 等待集合进行有时限等待,同样不占用 cpu 时间
  • 当其它持锁线程调用 notify() 或 notifyAll() 方法,会按照一定规则唤醒等待集合中的有时限等待线程,恢复为可运行状态,并重新去竞争锁
  • 如果等待超时,也会从有时限等待状态恢复为可运行状态,并重新去竞争锁
  • 还有一种情况是调用 sleep(long) 方法也会从可运行状态进入有时限等待状态,但与 Monitor 无关,不需要主动唤醒,超时时间到自然恢复为可运行状态
    6、TERMINATED(终结)
  • 线程内代码已经执行完毕,由可运行进入终结
  • 此时会取消与底层线程关联
    image-20230503203629212

2、在 java 中 wait 和 sleep 方法的不同?

共同点

  • wait () ,wait (long) 和 sleep (long) 的效果都是让当前线程暂时放弃 CPU 的使用权,进入阻塞状态

不同点

  • 方法归属不同

    • sleep (long) 是 Thread 的静态方法
    • 而 wait (),wait (long) 都是 Object 的成员方法,每个对象都有
  • 醒来时机不同

    • 执行 sleep (long) 和 wait (long) 的线程都会在等待相应毫秒后醒来
    • wait (long) 和 wait () 还可以被 notify 唤醒,wait () 如果不唤醒就一直等下去
    • 它们都可以被打断唤醒
  • 锁特性不同(重点)

    • wait 方法的调用必须先获取 wait 对象的锁,而 sleep 则无此限制(也就是 wait 必须和 synchronized 一起使用)
    • wait 方法执行后会释放对象锁,允许其它线程获得该对象锁(我放弃 cpu,但你们还可以用)
    • 而 sleep 如果在 synchronized 代码块中执行,并不会释放对象锁(我放弃 cpu,你们也用不了)
public class WaitSleepCase {  
​  
    static final Object LOCK = new Object();  
​  
    public static void main(String[] args) throws InterruptedException {  
        sleeping();  
    }  
​  
    private static void illegalWait() throws InterruptedException {  
        LOCK.wait();  
    }  
}
 private static void waiting() throws InterruptedException {  
        Thread t1 = new Thread(() -> {  
            synchronized (LOCK) {  
                try {  
                    get("t").debug("waiting...");  
                    LOCK.wait(5000L);  
                } catch (InterruptedException e) {  
                    get("t").debug("interrupted...");  
                    e.printStackTrace();  
                }  
            }  
        }, "t1");  
        t1.start();  
​  
        Thread.sleep(100);  
        synchronized (LOCK) {  
            main.debug("other...");  
        }  
​  
    }  

运行结果:
image.png

private static void sleeping() throws InterruptedException {  
        Thread t1 = new Thread(() -> {  
            synchronized (LOCK) {  
                try {  
                    get("t").debug("sleeping...");  
                    Thread.sleep(5000L);  
                } catch (InterruptedException e) {  
                    get("t").debug("interrupted...");  
                    e.printStackTrace();  
                }  
            }  
        }, "t1");  
        t1.start();  
​  
        Thread.sleep(100);  
        synchronized (LOCK) {  
            main.debug("other...");  
        }  
    }  

运行结果:
image.png

[!info]
1、wait 在使用的时候会释放掉和 synchronized 一起使用时锁住的对象,其他线程可以正常执行。
2、sleep 不会释放,会死占锁。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东莞呵呵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值