sleep和wait区别,并且查看线程运行状态

一、sleep和wait区别

区别一:语法使用不同

wait 方法必须配合 synchronized 一起使用,不然在运行时就会抛出 IllegalMonitorStateException 的异常

而 sleep 可以单独使用,无需配合 synchronized 一起使用。

区别二:所属类不同

wait 方法属于 Object 类的方法,而 sleep 属于 Thread 类的方法

区别三:唤醒方式不同

sleep 方法必须要传递一个超时时间的参数,且过了超时时间之后,线程会自动唤醒。而 wait 方法可以不传递任何参数,不传递任何参数时表示永久休眠,直到另一个线程调用了 notify 或 notifyAll 之后,休眠的线程才能被唤醒。也就是说 sleep 方法具有主动唤醒功能,而不传递任何参数的 wait 方法只能被动的被唤醒

区别四:释放锁资源不同

wait 方法会主动的释放锁,而 sleep 方法则不会。接下来我们使用代码的方式来演示一下二者的区别。

sleep 不释放锁

接下来使用 sleep 是线程休眠 2s,然后在另一个线程中尝试获取公共锁,如果能够获取到锁,则说明 sleep 在休眠时会释放锁,反之则说明不会释放锁,

在调用了 sleep 之后,在主线程里尝试获取锁却没有成功,只有 sleep 执行完之后释放了锁,主线程才正常的得到了锁,这说明 sleep 在休眠时并不会释放锁。

wait 释放锁

接下来使用同样的方式,将 sleep 替换成 wait,在线程休眠之后,在另一个线程中尝试获取锁,

当调用了 wait 之后,主线程立马尝试获取锁成功了,这就说明 wait 休眠时是释放锁的

区别五:线程进入状态不同

调用 sleep 方法线程会进入 TIMED_WAITING 有时限等待状态,而调用无参数的 wait 方法,线程会进入 WAITING 无时限等待状态。

总结

sleep 和 wait 都可以让线程进入休眠状态,并且它们都可以响应 interrupt 中断,但二者的区别主要体现在:语法使用不同、所属类不同、唤醒方式不同、释放锁不同和线程进入的状态不同。 ​

二、线程的状态Thread.State

三、供参考的多线程代码一、sleep和wait(WAITING和TIMED_WAITING状态)

java 复制代码
public class Test04_ThreadState {

    public static void main(String[] args) {
        new Thread(new TimeWaiting(), "TimeWaitingThread").start();
        new Thread(new Waiting(), "WaitingThread").start();

    }
    /**
     * 该线程不断的进行睡眠
     */
    static class TimeWaiting implements Runnable {
        @Override
        public void run() {
            while (true) {
                SleepUtils.second(100);
            }
        }
    }
    /**
     * 该线程在Waiting.class实例上等待
     */
    static class Waiting implements Runnable {
        @Override
        public void run() {
            while (true) {
                synchronized (Waiting.class) {
                    try {
                        Waiting.class.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}

四、查看线程运行状态的方法

1.jps

获得线程号和线程的类名

2.jstack + 线程号

jstack 2636

看线程某个时刻的运行情况(线程的快照)

这里打印出来的是当前线程的快照dump。

3.jvisualvm(可视化软件)

在java的jdk目录下的bin目录下有jvisualvm.exe文件,可以

打开软件后可以看到正在运行的进程,如下图

可以在其中找到java代码创建的线程的名字对应的线程

可以看到WatingThread线程状态是WAITING,++等待++状态

TimeWaitingThread线程状态是TIMED_WAITING,++超时等待++状态

和我们这篇文章的 二、线程的状态Thread.State对应。

五、案例

一、Blocked++阻塞++状态

Blocked++阻塞++状态代码

java 复制代码
public class Test04_ThreadState {

    public static void main(String[] args) {
        new Thread(new Blocked(), "BlockedThread-1").start();
        new Thread(new Blocked(), "BlockedThread-2").start();
    }
    
    /**
     * 该线程在Blocked.class实例上加锁后,不会释放该锁
     */
    static class Blocked implements Runnable {
        @Override
        public void run() {
            synchronized (Blocked.class) {
                while (true) {
                    SleepUtils.second(100);
                }
            }
        }
    }
}

Blocked++阻塞++状态代码jvisualvm查看

由于BlockedThread-1先创建,抢占到了系统资源,运行后拿到了锁,并调用了sleep方法,因此进入TIMED_WAITING++超时等待++ 状态,而BlockedThread-2拿不到锁,因此进入Blocked++阻塞++状态。线程快照dump如下图:

Blocked++阻塞++状态代码总结

1.触发Blocked状态的原因

由于BlockedThread-1先创建,抢占到了系统资源,运行后拿到了锁,并调用了sleep方法,因此进入TIMED_WAITING++超时等待++ 状态,而BlockedThread-2拿不到锁,因此进入Blocked++阻塞++状态。

2.sleep方法

由于sleep方法不会释放锁,因此BlockedThread-2无法拿到锁,进入阻塞状态,更加验证了sleep方法不会释放锁。

二、ReentrantLock可重入锁

ReentrantLock可重入锁代码

java 复制代码
public class Test04_ThreadState {

    private static Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        new Thread(new Sync(), "SyncThread-1").start();
        new Thread(new Sync(), "SyncThread-2").start();
    }
   
    static class Sync implements Runnable {

        @Override
        public void run() {
            lock.lock();
            try {
                SleepUtils.second(100);
            } finally {
                lock.unlock();
            }
        }

    }
}

ReentrantLock可重入锁代码jvisualvm查看

ReentrantLock可重入锁代码总结

1.synchronized和ReentrantLock区别(简略描述,之后会详细补充)

ReentrantLock锁更加面向对象

两个锁加锁之后另外一个线程进入状态不一样

synchronized进入blocked状态是被动的 还没有进入到同步代码块中

ReentrantLock是一种主动进入锁的状态 已经进入到代码块中 程序恢复之后 它会从等待的位置继续执行

最后总结:

a.线程的状态

jps看线程的线程号

jstack看线程某个时刻的运行情况(线程的快照)

jvisualvm对线程进行dump

b.线程调用sleep

进入TimeWaiting状态 不会释放锁

c.线程调用wait

进入Waiting状态 会释放锁

d.A线程进入B线程已经拿到锁(synchronized)

A线程会进入阻塞状态blocked状态

e.当A线程进入B线程已经拿到锁(lock)

A线程会进入等待状态waiting状态

f.synchronized和lock区别

1.lock锁更加面向对象

2.两个锁加锁之后另外一个线程进入状态不一样:

synchronized是blocked状态,lock是waiting状态

3.synchronized进入blocked状态是被动的 还没有进入到同步代码块中

4.lock是一种主动进入锁的状态 已经进入到代码块中 程序恢复之后 它会从等待的位置继续执行

如果你不太理解synchronized锁的对象是什么,你可以看下面这篇文章:

synchronized锁的对象是什么

相关推荐
juniperhan11 分钟前
Flink 系列第21篇:Flink SQL 函数与 UDF 全解读:类型推导、开发要点与 Module 扩展
java·大数据·数据仓库·分布式·sql·flink
ID_1800790547312 分钟前
Python 实现亚马逊商品详情 API 数据准确性校验(极简可用 + JSON 参考)
java·python·json
c++之路32 分钟前
C++23概述
java·c++·c++23
专注API从业者1 小时前
Open Claw 京东商品监控选品实战:一键抓取、实时监控、高效选品
java·服务器·数据库
摇滚侠2 小时前
DBeaver 导入数据库 导入 SQL 文件 MySQL 备份恢复
java·数据库·mysql
keep one's resolveY2 小时前
SpringBoot实现重试机制的四种方案
java·spring boot·后端
天空属于哈夫克33 小时前
企业微信API常见的错误和解决方案
java·数据库·企业微信
摇滚侠3 小时前
VMvare 虚拟机 Oracle19c 安装步骤,远程连接 Oracle19c,百度网盘安装包
java·oracle
梁萌3 小时前
idea报错找不到XX包的解决方法
java·intellij-idea·启动报错·缺少包
Agent产品评测局4 小时前
生产排期与MES/ERP系统打通,实操方法详解 —— 2026企业级智能体自动化选型与实战指南
java·运维·人工智能·ai·chatgpt·自动化