wait() notify() notifyAll()

  • wait和notify方法必须写在synchronized方法内,即在调用wait和notify方法前,需先获得对象锁;
  • 调用wait方法则释放锁;wait方法返回后,需获得对象锁才可继续执行下面语句;
  • 多个线程wait时,若另外的线程调用notify方法后,由JVM决定唤醒其中一个线程;
  • 多个线程wait时,若另外的线程调用notifyAll方法,则唤醒所有wait线程,但是只有其中一个线程可以获得对象锁,执行wait下面的语句,其余的等待释放对象锁后才可执行;
  • 调用notify/notifyAll时,线程并没有释放对象锁,只是其余线程被唤醒,但仍无法执行,只有等调用完notify/notifyAll并退出synchronized块,释放对象锁后,其余线程中的一个才可获得锁执行。
wait(),notify()/notityAll()方法是普通对象的方法(Object超类中实现),而不是线程对象的方法]

[wait(),notify()/notityAll()方法只能在同步方法中调用]


===================================================
sleep()


另:sleep方法使当前线程暂停执行一段时间,从而让其他线程有机会继续执行,但它并不释放对象锁。也就是说,如果有Synchronized块,其他线程仍然不能访问共享数据。

举生产者-消费者例子来说:仓库提供两个同步方法,一个put,一个get,假设put方法中线程sleep30秒,在这段时间中,get方法并不能从仓库中获取产品,因为sleep时并没有释放对象锁,所以调用get方法的线程不能执行。

假设有两个线程同时执行,都没有调用synchronized方法,一个线程优先级为MAX_PRIORITY,另一个为MIN_PRIORITY,如果没有sleep()方法,只有高优先级的线程执行完成后,低优先级的线程才能执行;但当高优先级的线程sleep(5000)后,低优先级就有机会执行了。

即:sleep方法可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级的线程获得执行的机会。

===================================================
wait() 区别 sleep()

1、这两个方法来自不同的类分别是,

sleep()来自Thread类,

wait()来自Object类。

sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用了b的sleep方法,实际上还是a去睡觉,要让b线程睡觉要在b的代码中调用sleep。

2、最主要

sleep方法没有释放锁

而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。

sleep不出让系统资源;wait是进入线程等待池等待,出让系统资源,其他线程可以占用CPU。一般wait不会加时间限制,因为如果wait线程的运行资源不够,再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,才会进入就绪队列等待OS分配系统资源。sleep(milliseconds)可以用时间指定使它自动唤醒过来,如果时间不到只能调用interrupt()强行打断。

Thread.Sleep(0)的作用是“触发操作系统立刻重新进行一次CPU竞争”。

3、使用范围:wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用


synchronized(x){

x.notify()

//或者wait()

}

4、sleep必须捕获异常

而wait,notify和notifyAll不需要捕获异常

===================================================

[synchornized方法]



  如果一个方法声明为synchornized的,则等同于在这个方法上调用synchornized(this).



  如果一个静态方法被声明为synchornized,则等同于在这个方法上调用synchornized(类.class).

现在进入wait方法和notify/notifyAll方法.这两个(或叫三个)方法都是Object对象的方法,而不是线程对象的方法.如同锁一样,它们是在线程中调用某一对象上执行的.

  class Test{

    public synchornized void test(){

    //获取条件,int x 要求大于100;

    

        if(x < 100)   // 最好使用while(x<100)

          wait();    //即 this.wait()

    }

  }



  这里为了说明方法没有加在try{}catch(){}中,如果没有明确在哪个对象上调用wait()方法,则为this.wait();

假如:

Test t = new Test();

现在有两个线程都执行到t.test();方法.其中线程A获取了t的对象锁,进入test()方法内.这时x小于100,所以线程A进入等待.

当一个线程调用了wait方法后,这个线程就进入了这个对象的休息室(waitset),这是一个虚拟的对象,但JVM中一定存在这样的一个数据结构用来记录当前对象中有哪些程线程在等待.



  当一个线程进入等待时,它就会释放锁,让其它线程来获取这个锁.



 线程A运行到this.wait(),  所以线程B有机会获得了线程A释放的锁,进入test()方法,如果这时x还是小于100,线程B也进入了t的休息室.这两个线程只能等待其它线程调用notity[All]来唤醒.



  但是如果调用的是有参数的wait(time)方法,则线程A,B都会在休息室中等待这个时间后自动唤醒.







  [为什么真正的应用都是用while(条件)而不用if(条件)]

  在实际的编程中我们看到大量的例子都是用     

        while(x < 100)

          wait();

go();而不是用if,为什么呢?

  在多个线程同时执行时,if(x <100)是不安全的.因为如果线程A和线程B都在t的休息室中等待,

这时另一个线程使x==100了,并调用notifyAll方法,线程A继续执行下面的go().而它执行完成后,x有可能又小于100,比如下面的程序中调用了--x,这时切换到线程B,线程B没有继续判断,直接执行go();就产生一个

错误的条件,只有while才能保证线程B又继续检查一次.

  



  [notify/notifyAll方法]

  这两个方法都是把某个对象在休息区内的线程唤醒, notify只能唤醒一个,但究竟是哪一个不能确定,而notifyAll则唤醒这个对象上的休息室中所有的线程.

  一般为了安全性,我们在绝对多数时候应该使用notifiAll(),  除非你明确知道只唤醒其中的一个线程.

那么是否是只要调用一个对象的wait()方法,当前线程就进入了这个对象的休息室呢?

事实中,要调用一个对象的wait()方法,只有当前线程获取了这个对象的锁 ,   换句话说一定要在这个对象的同步方法 或
以这个对象为参数的同步块中.

class MyThread extends Thread{

Test t = new Test();

  public void run(){

    t.test();

    System.out.println("Thread say:Hello,World!");

  }

}







public class Test {

  int x = 0;

  public void test(){

    if(x==0)

    try{

      wait();   // 即this.wait()     wait()要放到同步代码块里面

}

catch(Exception e){}

}

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

    new MyThread().start();

  }

}



这个线程就不会进入t的wait方法而直接打印出Thread say:Hello,World!.

而如果改成:

public class Test {



  int x = 0;

  public synchornized void test(){

    if(x==0)

    try{

      wait();

    }catch(Exception e){}

  }

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

    new MyThread().start();

  }

}

我们就可以看到线程一直等待,   注意这个线程进入等待后没有其它线程唤醒,   除非强行退出JVM环境,否则它一直等待.







所以请记住:

1,线程要想调用一个对象的wait()方法就要先获得该对象的监视锁,而一旦调用wait()后又立即释放该锁



2,如果要把notify/notifyAll和wait方法放在一起用的话,必须先调用notify/notifyAll后调用wait,因为如果调用完wait,该线程就已 

经不是current thread了



3,wait(),notify(),notifyAll()方法必须出现在同步方法或同步代码块中

wait() 区别 sleep()的更多相关文章

  1. c#与java的区别

    经常有人问这种问题,用了些时间java之后,发现这俩玩意除了一小部分壳子长的还有能稍微凑合上,基本上没什么相似之处,可以说也就是马甲层面上的相似吧,还是比较短的马甲... 一般C#多用于业务系统的开发 ...

  2. jquery和Js的区别和基础操作

    jqery的语法和js的语法一样,算是把js升级了一下,这两种语法可以一起使用,只不过是用jqery更加方便 一个页面想要使用jqery的话,先要引入一下jqery包,jqery包从网上下一个就可以, ...

  3. 【原】nodejs全局安装和本地安装的区别

    来微信支付有2年多了,从2年前的互联网模式转变为O2O模式,主要的场景是跟线下的商户去打交道,不像以往的互联网模式,有产品经理提需求,我们帮忙去解决问题. 转型后是这样的,团队成员更多需要去寻找业务的 ...

  4. 探究@property申明对象属性时copy与strong的区别

    一.问题来源 一直没有搞清楚NSString.NSArray.NSDictionary--属性描述关键字copy和strong的区别,看别人的项目中属性定义有的用copy,有的用strong.自己在开 ...

  5. X86和X86_64和X64有什么区别?

    x86是指intel的开发的一种32位指令集,从386开始时代开始的,一直沿用至今,是一种cisc指令集,所有intel早期的cpu,amd早期的cpu都支持这种指令集,ntel官方文档里面称为&qu ...

  6. Java中Comparable与Comparator的区别

    相同 Comparable和Comparator都是用来实现对象的比较.排序 要想对象比较.排序,都需要实现Comparable或Comparator接口 Comparable和Comparator都 ...

  7. MySQL中interactive_timeout和wait_timeout的区别

    在用mysql客户端对数据库进行操作时,打开终端窗口,如果一段时间没有操作,再次操作时,常常会报如下错误: ERROR (HY000): Lost connection to MySQL server ...

  8. 设置line-height:1.5和line-height:150%或者line-height:150px的区别

    直接正题: 看一下line-height可能的值: 其实可以分为两类: (1)不带单位的(如line-height:1.5),这种是推荐使用的: (2)带单位的(如line-heigth:30px/1 ...

  9. C#中Length和Count的区别(个人观点)

    这篇文章将会很短...短到比你的JJ还短,当然开玩笑了.网上有说过Length和count的区别,都是很含糊的,我没有发现有 文章说得比较透彻的,所以,虽然这篇文章很短,我还是希望能留在首页,听听大家 ...

  10. select、poll、epoll之间的区别总结

    select.poll.epoll之间的区别总结 05/05. 2014 select,poll,epoll都是IO多路复用的机制.I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪 ...

随机推荐

  1. SDOI2017round1酱油记day0

    嗯... 现在是21:12...准备睡了. 睡前写下day0一天如何过的: 早上5点起床到教室早自习,迷迷糊糊的宣誓,背东西,英语听写: 都停课了为什么还要上早自习! 我!想!去!机!房! OI才是我 ...

  2. Codeforces 898 B.Proper Nutrition

    B. Proper Nutrition   time limit per test 1 second memory limit per test 256 megabytes input standar ...

  3. POJ 3368 Frequent values 线段树与RMQ解法

    题意:给出n个数的非递减序列,进行q次查询.每次查询给出两个数a,b,求出第a个数到第b个数之间数字的最大频数. 如序列:-1 -1 1 1 1 1 2 2 3 第2个数到第5个数之间出现次数最多的是 ...

  4. 2016北京集训测试赛(十六)Problem B: river

    Solution 这题实际上并不是构造题, 而是一道网络流. 我们考虑题目要求的一条路径应该是什么样子的: 它是一个环, 并且满足每个点有且仅有一条出边, 一条入边, 同时这两条边的权值还必须不一样. ...

  5. WinSCP介绍、安装、使用(转)

    http://blog.csdn.net/liang19890820/article/details/49700931 前言 如果说XManager通过Xshell.Xftp可以很方便的进行远程管理, ...

  6. 安卓Webview缓存网页数据(无网络正常显示)

    热度 1已有 52 次阅读2016-8-26 17:53 |个人分类:常见问题|系统分类:移动开发 一.需求经历 最近的项目是一个原生 +webview 显示的 APP,一开始的时候,网站那边要求我们 ...

  7. dedecms 调用栏目或文章所属上下级关系

    效果如下: 代码如下: <div class="place"> <strong>当前位置:</strong> {dede:field name= ...

  8. 14. Spring Boot定时任务的使用【从零开始学Spring Boot】

    com.kfit.base.scheduling.SchedulingConfig: package com.kfit.base.scheduling; import org.springframew ...

  9. AngularJS的稍复杂form验证

    代码下载:https://files.cnblogs.com/files/xiandedanteng/angularjsSoccerFormCheck.rar 代码: <!DOCTYPE HTM ...

  10. Docker 开源管理工具集锦

    俗话说工欲善其事.必先利其器.Docker 是一种详细的虚拟化技术,Docker 尽管以RestAPI形式提供服务.但在实际生产环境中,管理大规模集群部署的Docker容器确实是一个巨大的挑战.尽管D ...