一.查看API

sleep是Thread类的方法,导致此线程暂停执行指定时间,给其他线程执行机会,但是依然保持着监控状态,过了指定时间会自动恢复,调用sleep方法不会释放锁对象。

当调用sleep方法后,当前线程进入阻塞状态。目的是让出CPU给其他线程运行的机会。但是由于sleep方法不会释放锁对象,所以在一个同步代码块中调用这个方法后,线程虽然休眠了,但其他线程无法访问它的锁对象。这是因为sleep方法拥有CPU的执行权,它可以自动醒来无需唤醒。而当sleep()结束指定休眠时间后,这个线程不一定立即执行,因为此时其他线程可能正在运行。

wait方法是Object类里的方法,当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时释放了锁对象,等待期间可以调用里面的同步方法,其他线程可以访问,等待时不拥有CPU的执行权,否则其他线程无法获取执行权。当一个线程执行了wait方法后,必须调用notify或者notifyAll方法才能唤醒,而且是随机唤醒,若是被其他线程抢到了CPU执行权,该线程会继续进入等待状态。由于锁对象可以时任意对象,所以wait方法必须定义在Object类中,因为Obeject类是所有类的基类。

二.是否可以传入参数

sleep()方法必须传入参数,参数就是休眠时间,时间到了就会自动醒来。

wait()方法可以传入参数也可以不传入参数,传入参数就是在参数结束的时间后开始等待,不穿如参数就是直接等待。

三.是否需要捕获异常

sleep方法必须要捕获异常,而wait方法不需要捕获异常。sleep方法属于Thread类中方法,表示让一个线程进入睡眠状态,等待一定的时间之后,自动醒来进入到可运行状态,不会马上进入运行状态,因为线程调度机制恢复线程的运行也需要时间,一个线程对象调用了sleep方法之后,并不会释放他所持有的所有对象锁,所以也就不会影响其他进程对象的运行。但在sleep的过程中过程中有可能被其他对象调用它的interrupt(),产生InterruptedException异常,如果你的程序不捕获这个异常,线程就会异常终止,进入TERMINATED状态,如果你的程序捕获了这个异常,那么程序就会继续执行catch语句块(可能还有finally语句块)以及以后的代码。

wait属于Object的成员方法,一旦一个对象调用了wait方法,必须要采用notify()和notifyAll()方法唤醒该进程;如果线程拥有某个或某些对象的同步锁,那么在调用了wait()后,这个线程就会释放它持有的所有同步资源,而不限于这个被调用了wait()方法的对象。wait()方法也同样会在wait的过程中有可能被其他对象调用interrupt()方法而产生。

四.作用范围

wait、notify和notifyAll方法只能在同步方法或者同步代码块中使用,而sleep方法可以在任何地方使用。但是注意sleep是静态方法,也就是说它只对当前对象有效。通过对象名.sleep()想让该对象线程进入休眠是无效的,它只会让当前线程进入休眠。

五.调用者的区别

首先为什么wait、notify和notifyAll方法要和synchronized关键字一起使用?

因为wait方法是使一个线程进入等待状态,并且释放其所持有的锁对象,notify方法是通知等待该锁对象的线程重新获得锁对象,然而如果没有获得锁对象,wait方法和notify方法都是没有意义的,因此必须先获得锁对象再对锁对象进行进一步操作于是才要把wait方法和notify方法写到同步方法和同步代码块中了。

由此可知,wait和notify、notifyAll方法是由确定的对象即锁对象来调用的,锁对象就像一个传话的人,他对某个线程说停下来等待,然后对另一个线程说你可以执行了(实质上是被捕获了),这一过程是线程通信。sleep方法是让某个线程暂停运行一段时间,其控制范围是由当前线程决定,运行的主动权是由当前线程来控制(拥有CPU的执行权)。

其实两者的区别都是让线程暂停运行一段时间,但本质的区别一个是线程的运行状态控制,一个是线程间的通信。

六.wait方法(线程通信)的一些注意事项

例如以下代码:

当线程print1获得了锁对象(this)后进行判断,如果不满足条件(flag == 1)无法继续执行下面的代码,于是进入wait状态。在另一个线程print3中,由于改变了flag,使得线程print1的判断条件满足了,线程print1就会被唤醒。

class Printer {
private int flag = 1;
public void print1() throws Exception {
synchronized(this) {
while(flag != 1) {
this.wait();
}
System.out.print("1");
System.out.print("2");
System.out.print("3");
System.out.print("4");
System.out.println();
flag = 2;
this.notifyAll();
}
}
public void print2() throws Exception {
synchronized(this) {
while(flag != 2) {
this.wait();
}
System.out.print("5");
System.out.print("6");
System.out.print("7");
System.out.print("8");
System.out.println();
flag = 3;
this.notifyAll();
}
}
public void print3() throws Exception {
synchronized(this) {
while(flag != 3) {
this.wait();
}
System.out.print("A");
System.out.print("B");
System.out.print("C");
System.out.print("D");
System.out.println();
flag = 1;
this.notifyAll();
}
}
}

注意事项:

1.调用wait方法和notify、notifyAll方法前必须获得对象锁,也就是必须写在synchronized(锁对象){......}代码块中。

2.当线程print1调用了wait方法后就释放了对象锁,否则其他线程无法获得对象锁,也就无法唤醒线程print1。

3.当this.wait()方法返回后,线程必须再次获得对象锁后才能继续执行。

4.如果另外两个线程都在wait,则正在执行的线程调用notify方法只能唤醒一个正在wait的线程(公平竞争,由JVM决定)。

5.当使用notifyAll方法后,所有wait状态的线程都会被唤醒,但是只有一个线程能获得锁对象,必须执行完while(condition){this.wait();}后才能获得对象锁。其余的需要等待该获得对象锁的线程执行完释放对象锁后才能继续执行。

6.当某个线程调用notifyAll方法后,虽然其他线程被唤醒了,但是该线程依然持有着对象锁,必须等该同步代码块执行完(右大括号结束)后才算正式释放了锁对象,另外两个线程才有机会执行。

sleep()和wait()的区别及wait方法的一点注意事项的更多相关文章

  1. Bootstrap栅栏布局里col-xs-*、col-sm-*、col-md-*、col-lg-*之间的区别及使用方法

    原文:Bootstrap栅栏布局里col-xs-*.col-sm-*.col-md-*.col-lg-*之间的区别及使用方法 版权声明:本文为博主原创文章,未经博主允许不得转载. https://bl ...

  2. 【JavaScript】call和apply区别及使用方法

    一.方法的定义call方法: 语法:fun.call(thisArg[, arg1[, arg2[, ...]]])定义:调用一个对象的一个方法,以另一个对象替换当前对象.说明:call 方法可以用来 ...

  3. python socket编程入门(编写server实例)+send 与sendall的区别与使用方法

    python 编写server的步骤: 1. 第一步是创建socket对象.调用socket构造函数.如: socket = socket.socket( family, type ) family参 ...

  4. GET方法和POST方法的区别,Get方法到底可传递的字符串的最大长度是多少?

    GET方法和POST方法的区别,Get方法到底可传递的字符串的最大长度是多少?曾经人介绍,如果使用GET方式传输参数,URL的最大长度是256个字节,对此深信不疑. 但是最近看到一些超长的url,能够 ...

  5. rt-thread中动态内存分配之小内存管理模块方法的一点理解

    @2019-01-18 [小记] rt-thread中动态内存分配之小内存管理模块方法的一点理解 > 内存初始化后的布局示意 lfree指向内存空闲区首地址 /** * @ingroup Sys ...

  6. Java8 Period.between方法坑及注意事项

    在使用Java8 新特性中关于Period.between的方法时需注意该方法获取日期的区间问题. @Test public void test1(){ LocalDate from = LocalD ...

  7. innerHTML,outerHTML,innerText,outerText区别以及insertAdjacentHTML()方法

    在需要给文档插入大量的新的HTML标记的情况下,通过多次DOM操作先创建节点再指定它们之间的关系会非常麻烦而且效率不高,相对而言插入标记的方法会更加简单,速度也更快. 插入标记中有这四个属性inner ...

  8. javascript的window.ActiveXObject对象,区别浏览器的方法

    (window.ActiveXObject)的作用,用来判断浏览器是否支持ActiveX控件,如果支持ActiveX控件,我们可以利用var xml=new ActiveXObject("M ...

  9. type of 操作符和instanceof操作符的区别以及使用方法

    经常见到用typeof和instanceof检测一个变量类型,作为前端小白经常不知道这两者具体的详细用法和区别,今天就整理一下谨记! javaScript中有6中数据类型: 1.Undefinde 2 ...

随机推荐

  1. jQuery中$.fn的用法

    原文:http://www.jb51.net/article/42816.htm $.fn是指jquery的命名空间,$.fn=$.prototype. 1.$.extend 为jquery添加静态方 ...

  2. 关于js函数中的异步编程

    大家都说js 是单线程的应用,但是随着技术的发展,js的发展已经不仅仅局限于单线程了.因为现在很多都是异步了,所谓的异步,就是类似于ajax,写了一个回调函数,当我的服务还在这个地方的时候,等着他去排 ...

  3. 解决android TextView多行文本(超过3行)使用ellipsize属性无效问题

    布局文件中的TextView属性 <TextView android:id="@+id/businesscardsingle_content_abstract" androi ...

  4. HttpActionDescriptor,ASP.NET Web API又一个重要的描述对象

    HttpActionDescriptor,ASP.NET Web API又一个重要的描述对象 通过前面对“HttpController的激活”的介绍我们已经知道了ASP.NET Web API通过Ht ...

  5. cocos2dx3.5 HTC One X 某些UI白屏或使用ClippingNode造成部分手机白屏

    public Cocos2dxGLSurfaceView onCreateView() { Cocos2dxGLSurfaceView glSurfaceView = new Cocos2dxGLSu ...

  6. DOCKER 从入门到放弃(二)

    搜索镜像 从docker官方镜像仓库搜索镜像 docker search [OPTIONS] TERM OPTIONS: --automated :只显示自动创建的镜像,默认值为fasle --fil ...

  7. 解决 CefSharp WPF控件不能使用输入法输入中文的问题(代码已提交到 github)

    首先,本文所有 代码已经提交到github,需要的可以直接从github获取:https://github.com/starts2000/CefSharp,希望可以帮助到有需要的朋友们. CEF 简介 ...

  8. 理解JAVA内存模型

    实际上java内存模型是如上图所示一样 每个线程有自己的栈内存,存放共享对象的副本,本地变量 每个线程自己的本地变量是不可见的,但是共享对象对每个线程都是可见的. 如果想实现线程通信的话, 线程对共享 ...

  9. LDA(线性判别分类器)学习笔记

    Linear Discriminant Analysis(线性判别分类器)是对费舍尔的线性鉴别方法(FLD)的归纳,属于监督学习的方法. LDA的基本思想是将高维的模式样本投影到最佳鉴别矢量空间,以达 ...

  10. 洛谷P3246 [HNOI2016]序列(离线 差分 树状数组)

    题意 题目链接 Sol 好像搞出了一个和题解不一样的做法(然而我考场上没写出来还是爆零0) 一个很显然的思路是考虑每个最小值的贡献. 预处理出每个数左边第一个比他小的数,右边第一个比他大的数. 那么\ ...