java多线程中sleep和wait的4个区别,你知道几个?

简介: sleep和wait的区别是面试中一个非常常见的问题,因为从表象来看,好像sleep和wait都能使线程处于阻塞状态,但是却有着本质上的却别。这篇文章就来好好分析一下。整体的区别其实是有四个:1、sleep是线程中的方法,但是wait是Object中的方法。2、sleep方法不会释放lock,但是wait会释放,而且会加入到等待队列中。3、sleep方法不依赖于同步器synchronized,但是wait需要依赖synchronized关键字。4、sleep不需要被唤醒(休眠之后推出阻塞),但是wait需要(不指定时间需要被别人中断)。下面我们就根据这四个区别来分析。

一、sleep是线程方法,wait是Object方法


这个如何验证呢?我们还需要到jdk源码中看看。首先进入到Thread的源码中看一下,然后俺ctrl+O就可以查看方法列表。在最上面可以搜寻,我们输入“s”,就可以查看所有以s开头的方法了。

v2-fca8c86c54edcf74a3e54f1529815959_1440w.jpg我们会发现,slee方法真实的在Thread线程类中。下面我们以同样的方法查看wait。

v2-60c7dc0f1755ccb54d46e5648433d767_1440w.jpg

这是第一个区别很容易验证,下面我们来看第二个。


二、sleep不释放lock,wait会释放


这个如何验证呢?这就需要代码了。先看我们的sleep方法

public class Test {
    private final static Object lock = new Object();
    public static void main(String[] args) {
        Stream.of("线程1","线程2").forEach(n->new Thread(n) {
            public void run(){
                Test.testSleep();
            }
        }.start());
    }
    //sleep方法休眠之后,
    private static void testSleep() {
        synchronized (lock) {
            try {
                System.out.println(Thread.currentThread().getName()
                                   +"正在执行");
                Thread.sleep(10_000);
                System.out.println(Thread.currentThread().getName()
                                   +"休眠结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

我们看一下运行结果:

v2-5d60e4351cfca47e4161539e6891c70d_1440w.png

在上面的结果中,线程2先获取了cpu资源,然后开始执行休眠,在休眠过程中线程1是没法执行的,必须要等待线程2结束之后才可以。这也就是说sleep方法不会释放锁,让其他线程进来。


然后我们测试一下wait方法。

public class Test {
    private final static Object lock = new Object();
    public static void main(String[] args) {
        Stream.of("线程1", "线程2").forEach(n -> new Thread(n) {
            public void run() {
                Test.testWait();
            }
        }.start());
    }
    private static void testWait() {
        synchronized (lock) {
            try {
                System.out.println(Thread.currentThread().getName()
                                   + "正在执行");
                lock.wait(10_000);
                System.out.println(Thread.currentThread().getName()
                                   + "wait结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在上面的例子中,我们使用wait方法等待10秒钟,然后结束。我们看一下结果:

v2-d99984ef90846c7d0aac6c400a97eaca_1440w.png

这个过程就验证了第二条区别,我们接下来看第三个。


三、sleep不依赖同步方法,wait需要


我们还是依次来验证。首先我们测试sleep方法。

public class Test2 {
    private final static Object lock = new Object();
    public static void main(String[] args) {
        Stream.of("线程1", "线程2").forEach(n -> new Thread(n) {
            public void run() {
                Test2.testSleep();
            }
        }.start());
    }
    private static void testSleep() {
        try {
            Thread.sleep(10_000);
            System.out.println("休眠结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

这个方法会依次运行,不会出现任何异常。然后我们主要是看wait方法。

public class Test2 {
    private final static Object lock = new Object();
    public static void main(String[] args) {
        Stream.of("线程1", "线程2").forEach(n -> new Thread(n) {
            public void run() {
                Test2.testSleep();
            }
        }.start());
    }
    private static void testWait() {
        try {
            lock.wait(10_000);
            System.out.println("wait结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

我们运行一下,看一下结果:

v2-50b186c8eac137b7dc185140789bfc59_1440w.jpg

OK,下面我们验证一下第四条区别:


四、sleep不需要被唤醒,wait需要


sleep方法很简单,我们主要关注wait方法。看代码:

首先我们定义两个方法,一个等待方法,一个唤醒方法。

public class Test2 {
    private final static Object lock = new Object();
    private static void testWait() {
        synchronized (lock) {
            try {
                System.out.println("我一直在等待");
                lock.wait();
                System.out.println("wait被唤醒了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    private static void notifyWait() {
        synchronized (lock) {
            try {
                Thread.sleep(5_000);
                lock.notify();
                System.out.println("休眠5秒钟唤醒wait");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

然后再去测试一下:

public class Test2 {
    private final static Object lock = new Object();
    public static void main(String[] args) {
        new Thread() {//这个线程一直在等待
            public void run() {
                Test2.testWait();
            }
        }.start();
        new Thread() {//这个线程准备去唤醒
            public void run() {
                Test2.notifyWait();
            }
        }.start();
    }
}

如果没有唤醒方法,那第一个线程就会处于一直等待的状态,第二个线程唤醒了之后就不再等待了。

v2-d51b34a7d0deff8f2f54464224062000_1440w.png

以上就是四个区别的完整验证,如有问题还请指正。


相关文章
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
517 0
|
Java 数据挖掘 调度
Java 多线程创建零基础入门新手指南:从零开始全面学习多线程创建方法
本文从零基础角度出发,深入浅出地讲解Java多线程的创建方式。内容涵盖继承`Thread`类、实现`Runnable`接口、使用`Callable`和`Future`接口以及线程池的创建与管理等核心知识点。通过代码示例与应用场景分析,帮助读者理解每种方式的特点及适用场景,理论结合实践,轻松掌握Java多线程编程 essentials。
888 5
|
监控 搜索推荐 Java
Java 多线程最新实操技术与应用场景全解析:从基础到进阶
本文深入探讨了Java多线程的现代并发编程技术,涵盖Java 8+新特性,如CompletableFuture异步处理、Stream并行流操作,以及Reactive编程中的Reactor框架。通过具体代码示例,讲解了异步任务组合、并行流优化及响应式编程的核心概念(Flux与Mono)。同时对比了同步、CompletableFuture和Reactor三种实现方式的性能,并总结了最佳实践,帮助开发者构建高效、扩展性强的应用。资源地址:[点击下载](https://pan.quark.cn/s/14fcf913bae6)。
695 3
|
算法 Java 调度
Java多线程基础
本文主要讲解多线程相关知识,分为两部分。第一部分涵盖多线程概念(并发与并行、进程与线程)、Java程序运行原理(JVM启动多线程特性)、实现多线程的两种方式(继承Thread类与实现Runnable接口)及其区别。第二部分涉及线程同步(同步锁的应用场景与代码示例)及线程间通信(wait()与notify()方法的使用)。通过多个Demo代码实例,深入浅出地解析多线程的核心知识点,帮助读者掌握其实现与应用技巧。
249 1
java 多线程异常处理
本文介绍了Java中ThreadGroup的异常处理机制,重点讲解UncaughtExceptionHandler的使用。通过示例代码展示了当线程的run()方法抛出未捕获异常时,JVM如何依次查找并调用线程的异常处理器、线程组的uncaughtException方法或默认异常处理器。文章还提供了具体代码和输出结果,帮助理解不同处理器的优先级与执行逻辑。
293 1
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
736 23
|
数据采集 存储 网络协议
Java HttpClient 多线程爬虫优化方案
Java HttpClient 多线程爬虫优化方案
|
Java API 微服务
为什么虚拟线程将改变Java并发编程?
为什么虚拟线程将改变Java并发编程?
555 83
|
11月前
|
Java
如何在Java中进行多线程编程
Java多线程编程常用方式包括:继承Thread类、实现Runnable接口、Callable接口(可返回结果)及使用线程池。推荐线程池以提升性能,避免频繁创建线程。结合同步与通信机制,可有效管理并发任务。
364 6
|
机器学习/深度学习 消息中间件 存储
【高薪程序员必看】万字长文拆解Java并发编程!(9-2):并发工具-线程池
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中的强力并发工具-线程池,废话不多说让我们直接开始。
484 0