首页 > 其他分享 >你真的理解wait()和sleep()吗

你真的理解wait()和sleep()吗

时间:2024-12-13 18:33:02浏览次数:5  
标签:对象 理解 线程 sleep 方法 类中 wait

wait()和sleep()

简单来说,都会进入阻塞状态,wait方法,直接释放锁,也就是对象的监视器,等待被唤醒,需要同Synchronized配合使用,sleep方法,不释放锁,等一定时间。

补充:

  1. 定义和所属类

    • wait()方法wait()方法是Object类中的方法。它用于使当前线程进入等待状态,直到其他线程调用该对象的notify()notifyAll()方法来唤醒它。这个方法通常在同步代码块或同步方法中使用,因为它需要获取对象的锁才能调用。

    • sleep()方法sleep()方法是Thread类中的静态方法。它会使当前线程暂停执行一段时间,这个时间是由方法参数指定的(以毫秒为单位)。线程在睡眠期间不会释放它已经获取的锁(如果有的话)。

  2. 使用场景和目的

    • wait()方法:

      • 线程间通信与协作:主要用于实现线程之间的协调和通信,特别是在共享资源的多线程环境中。例如,在生产者 - 消费者模型中,消费者线程在发现共享缓冲区为空时,可以调用wait()方法等待生产者生产数据。生产者生产完数据后,通过调用notify()notifyAll()方法唤醒等待的消费者线程。

      • 等待条件满足:当一个线程需要等待某个对象的状态满足特定条件才能继续执行时使用。比如,等待一个队列对象非空、等待一个任务完成的标志被设置等情况。

    • sleep()方法:

      • 简单的时间延迟:用于在不需要复杂的线程间交互的情况下,使线程暂停一段时间。例如,在一个定时任务中,线程完成一次任务后,通过sleep()方法暂停一段时间,然后再执行下一次任务。

      • 模拟长时间操作或调整执行节奏:在测试环境中,可以用sleep()方法来模拟一些耗时的操作,如网络延迟、文件读取时间等。在一些需要控制线程执行速度的场景下,也可以使用sleep()来调整线程的执行节奏。

  3. 对锁的处理方式

    • wait()方法:当一个线程调用wait()方法时,它会释放当前对象的锁。这是非常重要的一点,因为这样其他线程就可以获取该对象的锁并修改对象的状态,从而有可能使等待的条件得到满足。例如,在一个同步方法中,线程调用wait()后,其他线程就可以进入这个同步方法来改变对象的状态。

    • sleep()方法:线程在执行sleep()方法期间不会释放已经获取的锁。这意味着如果线程在持有锁的情况下进入睡眠状态,其他需要该锁的线程会被阻塞,直到睡眠的线程醒来并释放锁。这种行为可能会导致性能问题或者死锁情况,需要谨慎使用。

  4. 被唤醒后的行为和执行顺序

    • wait()方法:当线程被notify()notifyAll()方法唤醒后,它会重新尝试获取对象的锁。如果成功获取锁,线程会从wait()方法调用后的位置继续执行。需要注意的是,notify()方法只会随机唤醒一个等待在该对象上的线程,而notifyAll()方法会唤醒所有等待的线程,但是这些被唤醒的线程需要竞争锁,只有获取到锁的线程才能继续执行。

    • sleep()方法:线程睡眠结束后,会从sleep()方法调用后的位置继续执行,不需要重新获取锁(因为它在睡眠期间没有释放锁)。如果睡眠时间到了,但是当前线程没有获取到 CPU 资源,它会继续等待 CPU 分配时间片,一旦获得时间片就会继续执行。

wait 和 sleep 是否会触发锁的释放以及 CPU 资源的释放

Object.wait()方法,会释放锁资源以及 CPU 资源。

Thread.sleep()方法,不会释放锁资源,但是会释放 CPU 资源。

wait

wait()方法是让一个线程进入到阻塞状态,而这个方法必须写在一个 Synchronized 同步代码块里面。

因为 wait/notify 是基于共享内存来实现线程通信的工具,这个通信涉及条件的竞争,所以在调用这两个方法之前必须竞争锁资源。

(wait,释放已经获取的对象锁,然后进入等待状态,直到被其他线程唤醒,涉及对象监视器状态的改变;notify和notifyAll,用于通知正在等待该对象的其他线程,它们的操作同样涉及对象的监视器状态的改变,所以需要竞争锁资源)

当线程调用 wait 方法的时候,表示当前线程的工作处理完了,意味着让其他竞争同一个共享资源的线程有机会去执行。

但前提是其他线程需要竞争到锁资源,所以 wait 方法必须释放锁,否则就会导致死锁的问题。

sleep

只是让一个线程单纯进入睡眠状态,这个方法并没有强制要求加synchronized 同步锁。

而且从它的功能和语义来说,也没有这个必要。

当然,如果是在一个 Synchronized 同步代码块里面调用这个 Thread.sleep,也并不会触发锁的释放

最后,凡是让线程进入阻塞状态的方法,操作系统都会重新调度实现 CPU 时间片切换,这样设计的目的是提升 CPU 的利用率,所以都会释放CPU资源

  • yield()方法仅释放 CPU 执行权 , 锁仍然占用 , 线程会被放入就绪队列 ,会在短时间内再次执行。

为什么 wait() 方法不定义在 Thread 中?sleep() 方法为何定义在 Thread 类?

wait() 方法定义在 Object 类中,而不是 Thread 类中,这与 Java 的同步机制和对象锁管理息息相关

wait

  1. 与对象锁机制的紧密关联

在 Java 中,线程同步是基于对象级锁的,每个对象都有一个与之关联的监视器(monitor)。当线程想要进入某个同步代码块时,它必须首先获得该对象的锁。而 wait() 方法的设计目的是让线程在释放该对象的锁的同时,进入等待状态,等待其他线程的通知。

因为 wait() 与对象的锁机制密切相关,它操作的对象的监视器锁,而不是线程本身。因此,将 wait() 方法定义在 Object 类中更为合理,因为它本质上是针对对象锁的操作,而不是线程的行为。

  1. 线程在对象上等待

调用 wait() 时,线程是在某个对象上等待,即它等待的是某个对象的锁状态或条件的变化。这与线程自身的状态无关,而是依赖于对象的状态。因此,wait() 应该在 Object 类中,而不是在 Thread 类中,因为它的操作对象是锁定的资源,而不是线程。

sleep

wait() 不同,sleep() 方法定义在 Thread 类中,这是因为 sleep() 控制的是线程本身的行为,而不是对象的状态。

  1. sleep() 控制线程的执行节奏

sleep() 方法的作用是让当前线程暂停执行一段时间。它的功能仅仅是控制线程的休眠时间,而不涉及线程间的通信或对象锁。因此,将它定义在 Thread 类中是非常合适的,因为它直接影响线程的生命周期。

  1. sleep() 不涉及对象锁

sleep() 与对象的锁机制无关,线程调用 sleep() 后不会释放它所持有的任何锁。相反,线程在 sleep() 期间继续持有锁,只是暂停执行。因此,sleep() 是一个纯粹的线程行为控制方法,应该定义在 Thread 类中,而不是 Object 类中。

  1. 静态方法设计

sleep()Thread 类的静态方法,这意味着它影响的是当前正在运行的线程。无论哪个线程调用 Thread.sleep(),都表示当前线程需要休眠。将其定义为静态方法避免了通过特定的线程实例来调用,简化了使用方式。

补充:

  1. 为什么wait()方法不定义在Thread类中?

    • 从功能角度:

      • wait()方法的主要作用是让当前线程进入等待状态,直到其他线程调用notify()notifyAll()方法来唤醒它。这个方法是和对象的监视器(monitor)机制紧密相关的,用于实现线程之间的协作和同步。它实际上是用于控制对象的访问权限,而不是直接控制线程的行为。例如,在一个生产者 - 消费者模型中,生产者线程和消费者线程共享一个缓冲区对象。当缓冲区为空时,消费者线程调用wait()方法等待生产者生产数据,这个等待操作是基于缓冲区对象的状态,而不是线程本身的一个固有行为。

    • 从设计理念角度:

      • Java 的多线程设计中,Object类是所有类的根类。将wait()方法定义在Object类中,可以让所有的对象都具备这种等待 - 唤醒的协作机制。这样的设计使得任何对象都可以作为锁对象,并且在其上调用wait()notify()等方法来实现线程间的同步。如果wait()方法定义在Thread类中,就会限制这种同步机制只能在特定的线程相关对象上使用,不符合 Java 的面向对象和通用的多线程协作设计理念。

    • 从使用场景角度:

      • 一个线程可能会在多个对象上等待,比如在一个复杂的多线程应用程序中,一个线程可能需要等待多个共享资源(不同的对象)的状态变化。如果wait()方法在Thread类中,就很难方便地实现这种基于不同对象的等待操作。而通过将wait()方法放在Object类中,线程可以根据需要针对不同的对象进行等待操作,只需要获取对象的锁,就可以调用wait()方法进入等待状态。

  2. 为什么sleep()方法定义在Thread类?

    • 从功能角度:

      • sleep()方法的主要功能是让当前线程暂停执行一段时间。这是一种直接作用于线程本身的操作,它不涉及对象的监视器和线程间的协作同步机制。例如,一个简单的定时任务线程,它需要每隔一段时间执行一次任务,就可以使用sleep()方法来暂停自己的执行,等待下一个时间点到来。这种暂停操作是线程自身的行为,和任何特定的对象状态无关。

    • 从设计理念角度:

      • sleep()方法定义在Thread类中符合封装的原则,它明确地表示这是一个与线程自身运行状态相关的操作。这样的设计使得开发者能够直观地理解sleep()方法是用于控制线程本身的暂停,而不是与对象之间的同步相关。如果sleep()方法也像wait()方法一样定义在Object类中,会容易引起混淆,因为从功能上看,它和对象之间的同步等待没有直接关系。

    • 从使用场景角度:

      • 在实际的开发中,我们经常需要在不依赖于任何特定对象的情况下,暂停一个线程的执行。例如,在一个多线程的服务器应用程序中,一个后台线程可能需要定期检查一些系统资源的使用情况,它可以使用sleep()方法来设置检查的间隔时间,而不需要和其他对象的等待 - 唤醒机制关联在一起。将sleep()方法定义在Thread类中方便了这种与对象无关的、纯粹的线程暂停操作。

线程的 sleep()方法和 yield()方法有什么区别?

① sleep()方法给其他线程运行机会时不考虑线程的优先级 ,因此会给低优先级的线程以 运行的机

会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;

② 线程执行 sleep()方法后转入阻塞( blocked) 状态 , 而执行 yield()方法后转入就绪

( ready )状态;

③ sleep()方法声明抛出 Interrupted Exception , 而 yield()方法没有声明任何异常;

④ sleep()方法比 yield()方法( 跟操作系统 CPU 调度相关)具有更好的可移植性。

标签:对象,理解,线程,sleep,方法,类中,wait
From: https://blog.csdn.net/qq_62097431/article/details/144454958

相关文章

  • 【数字】异步复位同步释放的理解_解决sdc问题
    为什么复位也会引入亚稳态的问题?如下图是带复位端Rd和置位端Sd的DFF结构图。可以观察出Sd和Rd都会参与到Q输出的数据路径上,所以当异步时钟不满足recoverytime和removaltime的时候亚稳态还是会传播到Q端。复位信号引入了亚稳态会有危险吗?亚稳态导致的问题是当信号产生变......
  • 基于UI交互意图理解的异常检测方法2
     1.背景近年来,随着美团多种业务线的扩充和迭代,UI测试的任务愈发繁重。针对UI测试中人工成本过高的问题,美团到店测试团队开发了视觉自动化工具以进行UI界面的静态回归检查。然而,对于UI交互功能逻辑的检验仍强依赖于脚本测试,其无法满足对于进一步效率、覆盖面提升的强烈需求。......
  • 基于UI交互意图理解的异常检测方法14
     1.背景近年来,随着美团多种业务线的扩充和迭代,UI测试的任务愈发繁重。针对UI测试中人工成本过高的问题,美团到店测试团队开发了视觉自动化工具以进行UI界面的静态回归检查。然而,对于UI交互功能逻辑的检验仍强依赖于脚本测试,其无法满足对于进一步效率、覆盖面提升的强烈需求。......
  • 浅析 C# Async 和 Await 【代码之美系列】
    文章目录一、引言......
  • 第三章 3.1 表示图像 理解灰度图、RGB图和数组的关系
    图片与脚本文件放在一个文件夹内,同级。图片网上找一个就可以了。#https://github.com/PacktPublishing/Modern-Computer-Vision-with-PyTorch#https://github.com/PacktPublishing/Modern-Computer-Vision-with-PyTorch###################ChapterThree##############......
  • 网络通信与状态管理:深入理解Cookie、Session及Web工具
    前言:在当今数字化的网络世界中,Web技术的基石构建起了我们丰富多彩的互联网体验。其中,Cookie和Session犹如隐匿于幕后的关键使者,默默地在客户端与服务器之间传递着信息,管理着用户的状态与交互数据,深刻影响着我们在各类网站与应用中的每一次操作与交互流程。与此同时,Links、Wge......
  • 深入理解网络通信和TCPIP协议
    网络协议计算机网络是什么?随着计算机技术发展,计算机的体积和价格都在下降,之前计算机多用于研究机构,现阶段逐步进入一般的公司用于办公。原来计算机之间传输数据需要通过软盘等第三方存储介质进行转存,人们需要将数据直接通过通信线路传输,来缩短传输时间,于是计算机网络开始诞生......
  • 深入理解 JavaScript 柯里化: 提升函数的复用性和灵活性
    引言在JS编程中,函数是一等公民,具备了强大的灵活性和复用性。而柯里化作为一种高阶技术,可以进一步提升函数的复用性和灵活性。通过柯里化,可以大大简化函数的调用方式,并创建更加灵活和可复用的函数在本篇博客中,我们将深入探讨JS中柯里化的概念和原理,并......
  • HTTPS加密认证过程详细理解
    简单来说HTTPS也就是在HTTP基础上加上了SSL/TLS,SSL是TLS的前身,在建立TCP三次握手后,建立SSL/TLS四次握手,也是主要的加密认证过程。1、首先客户端先向服务端打招呼,并发送自己支持的TLS版本,选择的加密套件(支持的加密算法列表),以及随机生成的第1个随机数。对应12、接着服务端也......
  • 解题报告-论对“期望”的理解
    解题报告-论对“期望”的理解致敬传奇期望王这道题我写了\(5\)遍,每遍都没有思路,都是看题解或者自己之前的代码才写出来的。现在这里做一个这道题的总结,防止以后再出现这种情况。首先,这题看起来就很线性,但是我们不能一上来就\(f_i\)表示前\(i\)个点的分数期望,会发现很难转......