一.查看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. C#异步和多线程以及Thread、ThreadPool、Task区别和使用方法

    本文的目的是为了让大家了解什么是异步?什么是多线程?如何实现多线程?对于当前C#当中三种实现多线程的方法如何实现和使用?什么情景下选用哪一技术更好? 第一部分主要介绍在C#中异步(async/awai ...

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

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

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

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

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

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

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

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

随机推荐

  1. Intelij IDEA 内置 sql gui

    IDEA 内置 自带 SQL GUI  最大意义 会自动识别 domain 对象与数据表的关系,也可以通过 Database 的数据表直接生成 domain 对象等等. 第一步 打开数据库视图 Vie ...

  2. java使用类数组 报错Exception in thread "main" java.lang.NullPointerException

    源代码如下: Point[] points=new Point[n];//Point是一个类 for(int i=0;i<n;i++) { System.out.print("请输入x ...

  3. python---issubclass/type/isinstance/ 反射(内置函数getattr/delattr...)

    # 一 python面向对象-内置函数(issubclass(), type(), isinstance()) # issubclass 判断xxxx类是否是xxxx类的子类 class egg: p ...

  4. vi常用指令

    vi filename 打开文件 i 进入编辑模式 esc 退出编辑模式 : 进入指令模式 wq 保存退出 q!不存盘强制退出vi 按「a」进入插入模式后,是从目前光标所在位置的下一个位置开始输入文字 ...

  5. bae64编码

    data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAEAAAAkCAYAAABIdFAMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJb ...

  6. 20165234 《Java程序设计》第四周学习总结

    第四周学习总结 教材学习内容总结 第5章 子类与继承 子类的继承性 子类和父类在同一包中的继承性:子类继承父类中不是 private 的成员变量和方法作为自己的成员变量和方法 子类和父类不在同一包中的 ...

  7. java String、StringBuffer、StringBuild、StringTokenizer

    StringBuffer线程安全.StringBuilder线程不安全 效率: StringBuilder(线程不安全) > StringBuffer(线程安全) > String Str ...

  8. OGG初始化之使用Oracle Data Pump加载数据

    此方法使用Oracle Data Pump实用程序来建立目标数据.将副本应用于目标后,您将记录副本停止的SCN.包含在副本中的交易将被跳过以避免完整性违规冲突.从流程起点,Oracle GoldenG ...

  9. Netty实现简单私有协议

    本文参考<Netty权威指南> 私有协议实现的功能: 1.基于Netty的NIO通信框架,提供高性能异步通信能力 2.提供消息的编码解码框架,实现POJO的序列化和反序列化 3.提供基于I ...

  10. QR 编码原理(二)

    编码就是把常见的数字.字符等转换成QR码的方法.说具体的编码之前,先说一下QR码的最大容量问题. 一.最大容量 QR码的最大容量取决于选择的版本.纠错级别和编码模式(Mode:数字.字符.多字节字符等 ...