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. webpack 快速入门 系列 —— 实战一

    实战一 准备本篇的环境 虽然可以仅展示核心代码,但笔者认为在一个完整的环境中边看边做,举一反三,效果更佳. 这里的环境其实就是初步认识 webpack一文完整的示例,包含 webpack.devSer ...

  2. OpenCV on Mac OSX: A step-by-step guide

    I'm using OpenCV for my 4th year design project and setting it up was a huge pain. I had to look thr ...

  3. H5性能分析

    一.所有的浏览器都会支持一个W3C的标准 具体标准可以查看:https://www.w3.org/TR/navigation-timing/ 资源加载指标分析: Prompt for unload:访 ...

  4. margin (子元素远离父元素边框)

    如果父盒子没有设置border框着,那么他的子元素无法利用margin-top 来远离父元素的上边框 如果使用了margin-top会使子元素和父元素一起往下移 (子想离,父不设置border边框 则 ...

  5. LVS跨网段DR模型

    客户端IP地址:172.16.8.147 路由器服务器IP地址:172.16.8.167内网IP地址:192.168.1.3 一.将客户端的网关修改为路由服务器IP地址 vim ifcfg-ens33 ...

  6. [Python] 网络

    1.应用概念 应用层(Application Layer):将原始信息进行规范化描述,进而通过标准化接口与传输层对接 传输层(Transport Layer):实现信息的切分和重组,以及应用程序间的对 ...

  7. 华为eNSP模拟器— telnet实验

    华为eNSP模拟器-telnet实验 一.实验一 路由交换之间实现telnet登陆 实验拓扑 实验目的: 路由器作为 telnet 服务器 交换机作为客户端去连接路由器 实验步骤: 路由器配置 < ...

  8. Docker Swarm(十)Portainer 集群可视化管理

    前言 搭建好我们的容器编排集群,那我们总不能日常的时候也在命令行进行操作,所以我们需要使用到一些可视化的工具,Docker图形化管理提供了很多工具,有Portainer.Docker UI.Shipy ...

  9. Linux 操作系统(三) 添加用户、切换用户、删除用户

    以下命令均已在 Kali Linux 验证. 1.添加用户 --1-- useradd -m username            //username 代表你所添加的用户名 --2-- passw ...

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

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