sleep、wait方法之间区别

1.所属的类不同

sleep是Thread类的静态方法,而wait是Object类的成员方法

2.锁机制不一样

  • sleep方法:会让出资源调度器为当前线程分配的时间片,也就是放弃cpu的使用权,但是sleep不会释放当前线程持有的锁资源。其缺点就是当其它线程想获得同样的锁资源会被阻塞。
  • wait方法:既放弃cpu使用权,也会释放锁资源。即不会阻塞其它线程

请看如下代码:创建两个线程t1、t2,t1获得锁后睡眠5s

@Slf4j
public class TestSleepAndWait {
static final String lock = "abc";
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
synchronized (lock){
log.error("t1线程执行");
try {
//
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"t1"); Thread t2 = new Thread(()->{
// t2获得锁后执行
synchronized (lock){
log.error("t2线程执行");
}
},"t1"); t1.start();
t2.start();
}
}

执行结果:

16:51:01 [t1] gzhu.study.test.TestSleepAndWait - t1线程执行
16:51:06 [t1] gzhu.study.test.TestSleepAndWait - t2线程执行

由日志时间可以看到t2线程执行时间刚好在5s之后,说明t1睡眠过程中,t2一直在阻塞等待t1释放锁。

接下来我们尝试把sleep方法换成wait方法,上述其它代码不变

// t1线程等待
lock.wait();

查看运行结果:

16:57:55 [t1] gzhu.study.test.TestSleepAndWait - t1线程执行
16:57:55 [t1] gzhu.study.test.TestSleepAndWait - t2线程执行

可以看到t1、t2线程几乎在同一时间运行,说明wait方法使线程释放了说资源。值得注意的是,wait方法需要配合锁对象使用,即使用锁对象使当前线程阻塞。

3.调用之后的线程的状态不同

sleep方法调用后,线程进入TIME_WAITING状态,而wait方法调用后,线程会进入WAITING状态。

额外了解一下:什么是等待池?什么是锁池?

等待池就是:线程调用wait方法后,线程会进入一个LIFO(为什么是LIFO下面解释)等待被唤醒,在等待池的线程被唤醒之前是不会去竞争锁资源的。

锁池:存放竞争锁资源的线程,等待池的线程被notify()和notifyAll()方法唤醒之后,会先进入锁池而不是直接获得锁资源执行。另外有一个误区,笔者看到许多博客说sleep方法需要指定时间,而wait方法不需要指定时间其实是错的,如下:

public final native void wait(long timeout) throws InterruptedException;

public final void wait(long timeout, int nanos) throws InterruptedException

第一种情况:

@Slf4j
public class TestSleepAndWait {
static final String lock = "abc";
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
synchronized (lock){
log.error("t1线程执行");
try {
// t1线程等待
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.error("t1线程继续执行");
}
},"t1"); Thread t2 = new Thread(()->{
// t2获得锁后执行
synchronized (lock){
log.error("t2线程执行");
}
},"t1"); Thread t3 = new Thread(()->{
// t2获得锁后执行
synchronized (lock){
log.error("t3线程执行");
}
},"t3"); t1.start();
t2.start();
t3.start();
}
}

结果:

17:33:03 [t1] gzhu.study.test.TestSleepAndWait - t1线程执行
17:33:03 [t3] gzhu.study.test.TestSleepAndWait - t3线程执行
17:33:03 [t1] gzhu.study.test.TestSleepAndWait - t2线程执行

由于没有唤醒t1线程,即使t2、t3线程释放锁资源后,t1线程也没有继续执行。

第二种情况:

Thread t1 = new Thread(()->{
synchronized (lock){
log.error("t1线程执行");
try {
// t1线程等待
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.error("t1线程继续执行");
}
},"t1"); Thread t2 = new Thread(()->{
// t2获得锁后执行
synchronized (lock){
log.error("t2线程执行");
lock.notify();
while (true){ }
}
},"t1"); t1.start();
t2.start();

运行结果:

17:38:23 [t1] gzhu.study.test.TestSleepAndWait - t1线程执行
17:38:23 [t1] gzhu.study.test.TestSleepAndWait - t2线程执行

即使t1被t2唤醒进入锁池,但是由于t2一直循环未释放锁资源,使得t1也不能立即继续执行。

notify()方法与notifyAll()方法

notifAll方法,是将等待池中所有线程唤醒,并按照LIFO原则唤醒

notify方法是从等待队列中随机唤醒,如果只有一个线程则唤醒一个线程。

sleep、wait方法之间区别的更多相关文章

  1. jQuery的prop和attr方法之间区别

    JQuery.attr(): Get the value of an attribute for the first element in the set of matched elements. J ...

  2. jquery中使元素显示和隐藏方法之间的区别

    在实际的项目开发中,要使一个元素隐藏的方法有很多,比如css的多种属性和jquery的多种方法,虽然他们的作用都是使元素不可见,但是各个方法实现的原理是不一样的.下面主要介绍jquery各个元素隐藏方 ...

  3. 二.OC基础--1,对象的存储细节,2,#pragma mark指令,3,函数和对象方法的区别,4,对象和方法之间的关系 ,5.课堂习题

    1,对象的存储细节, 1. 当创建一个对象的时候:Person *p1 = [Person new],做了三件事情: 1,申请堆内存空间: 2,给实例变量初始化: 3,返回所申请空间的首地址; 2. ...

  4. 并查集类的c++封装,比較union_find algorithm四种实现方法之间的性能区别

    问题描写叙述: 在计算机科学中,并查集是一种树型的数据结构,其保持着用于处理一些不相交集合(Disjoint Sets)的合并及查询问题.有一个联合-查找算法(union-find algorithm ...

  5. ThinkPHP的D方法和M方法的区别

    M方法和D方法的区别 ThinkPHP 中M方法和D方法都用于实例化一个模型类,M方法 用于高效实例化一个基础模型类,而 D方法 用于实例化一个用户定义模型类. 使用M方法 如果是如下情况,请考虑使用 ...

  6. jQuery中的.bind()、.live()和.delegate()之间区别分析

    jQuery中的.bind()..live()和.delegate()之间区别分析,学习jquery的朋友可以参考下.   DOM树   首先,可视化一个HMTL文档的DOM树是很有帮助的.一个简单的 ...

  7. Hibernate框架之get和load方法的区别

    我们在学习Hibernate框架时,经常会进行修改,删除操作,对于这些操作,我们都应该先加载对象,然后在执行或删除的操作,那么这里Hibernate提供了两种方法按照主键加载对象,也就是我要说的get ...

  8. Java线程中yield与join方法的区别

    长期以来,多线程问题颇为受到面试官的青睐.虽然我个人认为我们当中很少有人能真正获得机会开发复杂的多线程应用(在过去的七年中,我得到了一个机会),但是理解多线程对增加你的信心很有用.之前,我讨论了一个w ...

  9. M方法和D方法的区别

    M方法和D方法的区别 ThinkPHP 中M方法和D方法都用于实例化一个模型类,M方法 用于高效实例化一个基础模型类,而 D方法 用于实例化一个用户定义模型类. 使用M方法 如果是如下情况,请考虑使用 ...

随机推荐

  1. ES6学习-4 解构赋值(1)数组的解构赋值

    解构赋值是ES6很大的一个提升,为我们带来了很多方便,但用不好,会使程序的可读性变差,所以用时要注意,尽量保持程序的易读性. 数组解构赋值 在JS没有支持解构赋值之前,我们声明几个变量并赋值通常都是像 ...

  2. shell脚本 在后台执行de 命令 >> 文件 2>&1 将标准输出与错误输出共同写入到文件中(追加到原有内容的后面)

    命令 >> 文件 2>&1或命令 &>> 文件 将标准输出与错误输出共同写入到文件中(追加到原有内容的后面) # ll >>aaa 2> ...

  3. 保存 yum 下载的软件包并制作成本地 yum 源

    保存 yum 下载的软件包并制作成本地 yum 源 实验对象 CentOS 7 yum 安装 nginx (nginx必须使用第三源才能安装:redhat8版本的则不需要,官网源自带nginx软件包) ...

  4. zabbix官方源替换为阿里云的zabbix源,一键脚本。(安装zabbix报错curl#18 - "transfer closed with 2988713 bytes remaining to read":15 ETA Trying other mirro)

    最近突然安装zabbix总是报错,比如 (24/27): t1lib-5.1.2-14.el7.x86_64.rpm | 166 kB 00:00:00 zabbix-web-4.4.6-1.el7. ...

  5. 那些天,shell脚本中曾经踩过的坑

    前些天,需要实现一个需求,用脚本轮流kill服务器上的进程,观察内存变化情况,并写日志.脚本逻辑不难,但shell脚本好久不用,看过书里的语法都忘得差不多了,中间踩了不少的坑,特此记录一下,留作后续参 ...

  6. TCP/IP、Http的区别--(转自任智康)

    TPC/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据.关于TCP/IP和HTTP协议的关系,网络有一段比较容易理解的介绍:"我们在传输数据 ...

  7. Question&&Answer

    1.使用Navicat连接Ubuntu上面的MySql数据库失败 解决办法:Navicat版本的问题,尝试换用更高版本的Navicat解决了问题(当时使用了Navicat Premium_11.2.7 ...

  8. 将 maven repo 部署到 Gitlab

    为什么要将 maven repo 部署到 Gitlab 将 Maven artifacts 放在对应的项目仓库下,而不是专门再去建一个 Maven 仓库.这么做使用起来更方便,更易于管理. 借助 Gi ...

  9. docker启动失败如何查看容器日志

    docker启动失败如何查看容器日志 在使用docker的时候,在某些未知的情况下可能启动了容器,但是过了没几秒容器自动退出了.这个时候如何排查问题呢? 通常碰到这种情况无非就是环境有问题或者应用有问 ...

  10. scrapy使用response.body时编码问题

    scrapy使用response.body时编码问题 摘要:scrapy使用response.body时编码问题.如果在使用responses.body获取数据时,需要将其编码转换成unicode,即 ...