• wait()和sleep()的区别


    —————————————————————————————————————————
    这两者的施加者是有本质区别的
    sleep()是让某个线程暂停运行一段时间,其控制范围是由当前线程决定,也就是说,在线程里面决定.好比如说,我要做的事情是 "点火->烧水->煮面",而当我点完火之后我不立即烧水,我要休息一段时间再烧.对于运行的主动权是由我的流程来控制.
     
    而wait(),首先,这是由某个确定的对象来调用的,将这个对象理解成一个传话的人,当这个人在某个线程里面说"暂停!",也是 thisOBJ.wait(),这里的暂停是阻塞,还是"点火->烧水->煮饭",thisOBJ就好比一个监督我的人站在我旁边,本来该线 程应该执行1后执行2,再执行3,而在2处被那个对象喊暂停,那么我就会一直等在这里而不执行3,但正个流程并没有结束,我一直想去煮饭,但还没被允许, 直到那个对象在某个地方说"通知暂停的线程启动!",也就是thisOBJ.notify()的时候,那么我就可以煮饭了,这个被暂停的线程就会从暂停处 继续执行.
     
     
    其实两者都可以让线程暂停一段时间,但是本质的区别是一个线程的运行状态控制,一个是线程之间的通讯的问题
     
    在java.lang.Thread类中,提供了sleep(),
    而java.lang.Object类中提供了wait(), notify()和notifyAll()方法来操作线程
    sleep()可以将一个线程睡眠,参数可以指定一个时间。
    而wait()可以将一个线程挂起,直到超时或者该线程被唤醒。
        wait有两种形式wait()和wait(milliseconds).
     
    —————————————————————————————————————————
    sleep和wait的区别
      1,这两个方法来自不同的类分别是Thread和Object
      2,最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
      3,wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在
        任何地方使用
       synchronized(x){
          x.notify()
         //或者wait()
       }
       4,sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
    —————————————————————————————————————————
    ————————————————————————————————————————— 
    sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。
    调用sleep不会释放对象锁。 
    sleep()使得一个进程进入睡眠状态,但是线程所占有的资源并没有释放。
    比如,你在synchronized模块(加函数锁或者对象锁)里面调用了sleep(),虽然线程睡着了而且没有使用资源,但是它依然保存着锁,别的线程依然无法调用相关的synchronized模块。
    sleep是Thread的静态类方法,谁调用的谁去睡觉。
    最主要是sleep方法没有释放锁不出让系统资源。
    sleep(milliseconds)可以用时间指定使它自动唤醒过来,如果时间不到只能调用interrupt()强行打断。
    Thread.sleep(0)的作用是“触发操作系统立刻重新进行一次CPU竞争”。
     
    —————————————————————————————————————————
    wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
    sleep来自Thread类,和wait来自Object类。
     
    wait方法释放了锁,使得其他线程可以使用同步控制块或者方法,wait是进入线程等待池等待,出让系统资源,其他线程可以占用CPU。一般wait不会加时间限制,因为如果wait线程的运行资源不够,再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,才会进入就绪队列等待OS分配系统资源。
     
    notify唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程。此方法只应由作为此对象监视器的所有者的线程来调用。
     
    调用对像wait方法后,当前线程释放对象锁,进入等待状态.直到其他线程(也只能是其他线程)通过notify 方法,或 notifyAll.该线程重新获得对像锁.
    继续执行,记得线程必须重新获得对像锁才能继续执行.因为synchronized代码块内没有锁是寸步不能走的。
     
    "当前的线程必须拥有此对象监视器"与"此方法只应由作为此对象监视器的所有者的线程来调用"说明wait方法与notify方法必须在同步块内执行,即synchronized(obj之内).
     
    使用范围:wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用。
     
       synchronized(x){ 
          x.notify() 
         //或者wait() 
       }
     
    —————————————————————————————————————————
    【wait()和notify()内部机制】
    wait(),notify(),notifyAll()不属于Thread类,而是属于Object基础类,也就是说每个对象都有wait(),notify(),notifyAll()的功能。
    因为【每个对象都有锁】,锁是每个对象的基础,当然操作锁的方法也是最基础了。
     
    wait():
    等待对象的同步锁,需要获得该对象的同步锁才可以调用这个方法,否则编译可以通过,但运行时会收到一个异常:IllegalMonitorStateException。
    调用任意对象的 wait() 方法导致该线程阻塞,该线程不可继续执行,并且该对象上的锁被释放。
     
    notify():
    唤醒在等待该对象同步锁的线程(只唤醒一个,如果有多个在等待),注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
    调用任意对象的notify()方法则导致因调用该对象的 wait()方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。
     
    notifyAll():
    唤醒所有等待的线程,注意唤醒的是notify之前wait的线程,对于notify之后的wait线程是没有效果的。
     
     —————————————————————————————————————————
    【Java使用wait/notify  机制是为了避免轮询带来的性能损失,跟synchronized关键字比较有什么好处呢?】
    若使用简单的synchonized机制实现互斥,会导致线程主动发起轮询,若N次轮询没有成功,就产生了N次的CPU空间浪费;
    如果加上了 wait/notify机制,就可以避免这些无谓的轮询,节省CPU的消耗。
     
    通常,多线程之间需要协调工作。例如,浏览器的一个显示图片的线程displayThread想要执行显示图片的任务,必须等待下载线程 downloadThread将该图片下载完毕。如果图片还没有下载完,displayThread可以暂停,当downloadThread完成了任务 后,再通知displayThread“图片准备完毕,可以显示了”,这时,displayThread继续执行。
    以上逻辑简单的说就是:如果【条件不满足,则等待】。当条件满足时,等待该条件的线程将被唤醒。
     
    在Java中,这个机制的实现依赖于wait/notify。等待机制与锁机制是密切关联的。例如:
    synchronized(obj) {while(!condition) {obj.wait();}obj.doSomething();}  
     
    当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait()。
    在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A:
    synchronized(obj) {condition = true;obj.notify();} 
     
    —————————————————————————————————————————
    需要注意的概念是:
    ◆调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {...} 代码段内。
    ◆调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {...} 代码段内唤醒A。
    ◆当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。
    ◆如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。
    ◆obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。
    ◆当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。
     
    ————————————————————————————————————————— 

  • 相关阅读:
    BZOJ_3159_决战
    11.19 ~ 11.25训练计划+总结
    BZOJ_1304_[CQOI2009]叶子的染色_树形DP
    BZOJ_1999_[Noip2007]Core树网的核_单调队列+树形DP
    BZOJ_4033_[HAOI2015]树上染色_树形DP
    BZOJ_5338_ [TJOI2018]xor_可持久化trie
    BZOJ_2957_楼房重建_线段树
    BZOJ_3124_[Sdoi2013]直径_树形DP
    BZOJ_4987_Tree_树形DP
    「JOISC 2019 Day2」两个天线(线段树)
  • 原文地址:https://www.cnblogs.com/lsx1993/p/4820194.html
Copyright © 2020-2023  润新知