当前位置: 首页 > article >正文

【Java】线程暂停比拼:wait() 和 sleep()的较量

欢迎浏览高耳机的博客

希望我们彼此都有更好的收获

感谢三连支持!

在Java多线程编程中,合理地控制线程的执行是至关重要的。wait()sleep()是两个常用的方法,它们都可以用来暂停线程的执行,但它们之间存在着显著的差异。本文将详细探讨这两个方法的区别,并提供一个实际的编程示例来展示如何使用它们来控制线程的执行顺序。

               当你被罚站时,需要等待解除罚站的指令才能离开;

               而当你睡觉时,到了一定时间自然就会醒来;

wait()sleep()概述

wait()

    定义wait()Object类的一个方法,它使得调用它的线程释放对象的锁,并进入对象的等待池(wait set)。

    用途:主要用于线程间的协作,特别是当一个线程需要等待另一个线程完成某些操作时。

    锁状态:调用wait()的线程必须拥有对象的锁,并且在调用后会释放这个锁。

sleep()

    定义sleep()Thread类的一个静态方法,它使得调用它的线程暂停执行指定的时间。

    用途:通常用于控制线程的执行时间,或者在不释放锁的情况下让其他线程有机会执行。

    锁状态:调用sleep()的线程不会释放任何锁。

wait()必须在同步方法或块中调用。

sleep()可以在任何地方调用。

区别详解

锁状态和对象监视器

    wait()需要在同步方法或块中调用,因为它依赖于对象的锁。调用后,线程会释放锁并进入等待状态。

    sleep()可以在任何地方调用,不需要在同步方法或块中,且不会释放任何锁。

响应中断

           在wait()sleep()期间,如果线程被中断,都会抛出InterruptedException异常。

用途

    wait()通常用于线程间的协作,如生产者-消费者问题。

    sleep()通常用于控制线程的执行时间,或者在不释放锁的情况下让其他线程有机会执行。

返回到执行状态

    wait()在被唤醒后,需要重新获得对象的锁才能继续执行。

    sleep()在睡眠时间结束后自动继续执行,不需要重新获得锁。

实际编程示例

以下是一个使用wait()sleep()来控制线程执行顺序的示例:

    有三个线程,线程名称分别为:a,b,c。 
    每个线程打印自己的名称。
    需要让他们同时启动,并按 c,b,a的顺序打印

使用 wait() 实现: 

package Thread;

public class Demo11 {

    private static Object locker = new Object();
    private static int state = 1;

    public static void main(String[] args) throws InterruptedException {

        //通过state这个变量作为判断条件,不满足该条件的线程进入等待,满足条件的线程则先打印,
        //然后改变条件,通过notify唤醒其他线程,继续判断,打印;

        Thread thread1 = new Thread(() -> {
            synchronized (locker) {
                while(state != 1) {
                    try {
                        locker.wait();
                    }catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("C");
                state = 2;
                locker.notify();
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (locker) {
                while(state != 2) {
                    try {
                        locker.wait();
                    }catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("B");
                state = 3;
                locker.notify();
            }
        });

        Thread thread3 = new Thread(() -> {
            synchronized (locker) {
                while(state != 3) {
                    try {
                        locker.wait();
                    }catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("A");
                state = 1;
                locker.notify();
            }
        });

        thread1.start();
        thread2.start();
        thread3.start();
        thread1.join();
        thread2.join();
        thread3.join();
    }
}

在这个示例中,我们使用了一个共享对象locker作为锁,并通过state变量来控制线程的执行顺序。每个线程在执行前都会检查state变量,如果不符合条件,就会调用wait()方法等待。当一个线程执行完毕后,它会更新state变量并调用notify()方法来唤醒其他等待的线程。

使用 sleep() 实现

package Thread;

public class Demo13 {
    //sleep版
//    有三个线程,线程名称分别为:a,b,c。
//    每个线程打印自己的名称。
//    需要让他们同时启动,并按 c,b,a的顺序打印


    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
                    try {
                        Thread.sleep(200);
                    }catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                System.out.println("C");
        });

        Thread thread2 = new Thread(() -> {
                    try {
                        Thread.sleep(400);
                    }catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                System.out.println("B");
        });

        Thread thread3 = new Thread(() -> {
                    try {
                        Thread.sleep(600);
                    }catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                System.out.println("A");
        });

        thread1.start();
        thread2.start();
        thread3.start();
        thread1.join();
        thread2.join();
        thread3.join();
    }
}

在这个实例中,我们不需要使用synchronized锁来帮助我们控制进程,而是单纯通过每个线程的睡眠时间不同,利用时间差来实现规定的打印顺序;

这种方法虽然更加直观,但请注意,这种方法并不是线程同步的推荐做法,因为它依赖于硬编码的延迟,这可能会导致不可预测的行为,特别是在不同的系统或不同的负载条件下。通常,使用waitnotifyReentrantLockCondition来实现线程间的协调是更可靠和可控的方法。 

结论

理解wait()sleep()的区别对于编写高效的多线程程序至关重要。wait()sleep()都可以用来暂停线程的执行,但它们在锁状态、用途、中断响应等方面有着显著的不同。正确使用这些方法可以帮助你更好地控制线程的执行顺序和协作。

 


http://www.kler.cn/news/315542.html

相关文章:

  • 安卓数据存储——SharedPreferences
  • Apifox 「定时任务」操作指南,解锁自动化测试的新利器
  • HTTPS:构建安全通信的基石
  • 关于es的一个多集群、多索引切换的实现
  • [leetcode刷题]面试经典150题之2移除元素(简单)
  • pycharm 使用 translation 插件通过openai进行翻译
  • 怎么能让电脑屏幕显示多个监控画面?电脑监控如何多画面显示?
  • 面向切面:单元测试、事务、资源操作
  • UDP实现组播发送端和接收端
  • [Redis] 渐进式遍历+使用jedis操作Redis+使用Spring操作Redis
  • 论文阅读 | 基于流模型和可逆噪声层的鲁棒水印框架(AAAI 2023)
  • 【机器学习】OpenCV入门与基础知识
  • 一种求解无人机三维路径规划的高维多目标优化算法,MATLAB代码
  • Java笔试面试题AI答之设计模式(1)
  • uni-app尺寸单位、flex布局于背景图片
  • Java ETL - Apache Beam 简介
  • 如何使用Privoxy将SOCKS5代理转换为HTTP代理?
  • 数据库(mysql)常用命令
  • 妈妈再也不用担心字符串方法啦!——js String实例方法汇总
  • PicoQuant公司:探索铜铟镓硒(CIGS)太阳能电池技术,引领绿色能源革新
  • MySQL之复合查询与内外连接
  • Qt 读写windows注册表
  • 深度学习02-pytorch-02-张量的拼接操作
  • 零工市场小程序:保障灵活就业
  • java(3)数组的定义与使用
  • 基于SpringBoot+WebSocket实现地图上绘制车辆实时运动轨迹图
  • ARM概念
  • android13 RK3588芯片,录音没有声音
  • AIGC时代算法工程师的面试秘籍(第二十二式2024.9.2-9.15) |【三年面试五年模拟】
  • SVN笔记-SVN安装