并发编程之wait和sleep的区别

目录

并发编程之wait和sleep的区别

一、区别

二、代码验证sleep

三、代码验证wait


一、区别

相同点:线程的状态相同,都是阻塞状态

不同点:

  1. wait是Object的状态,任何对象都可以调用;sleep时Thread的静态方法。
  2. wait必须配合synchronized关键字一起使用;如果一个对象没有获取到锁尝试直接调用wait会发生异常;sleep则不需要。
  3. wait可以通过notify主动叫醒,sleep只能通过打断主动叫醒。
  4. wait会释放锁,sleep在阻塞的阶段是不会释放锁的。

二、代码验证sleep

场景:多线程情况下,假设某个线程拿到锁了,但是它需要满足某个条件,才能执行,如果使用sleep,会导致在没有满足情况的条件下一直持有锁,别的线程也拿不到

/**
*/
@Slf4j(topic = "liheng")
public class TestWait1 {static final Object pc = new Object();static boolean isPrettyGril = false; // 有没有女人public static void main(String[] args) throws InterruptedException {new Thread(() -> {synchronized (pc) {log.debug("有没有女人[{}]", isPrettyGril);if (!isPrettyGril) {log.debug("没有女人!等女人,等5秒;别人也不能干活");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}log.debug("等了5秒 有没有女人?[{}]", isPrettyGril);if (isPrettyGril) {log.debug("------男女搭配干活不累;啪啪啪写完了代码");}else{log.debug("------下班回家----");}}}, "jack").start();for (int i = 0; i < 10; i++) {new Thread(() -> {synchronized (pc) {log.debug("我们10个屌丝工作了");}}, "其它人").start();}Thread.sleep(1000);new Thread(() -> {
//            synchronized (pc) {isPrettyGril = true;log.debug("桥本有菜来了");
//            }}, "boss").start();}
}
/**
-------------------------打印结果----------------------
16:02:28.679 [jack] DEBUG liheng - 有没有女人[false]
16:02:28.682 [jack] DEBUG liheng - 没有女人!等女人,等5秒;别人也不能干活
16:02:29.684 [boss] DEBUG liheng - 桥本有菜来了
16:02:33.685 [jack] DEBUG liheng - 等了5秒 有没有女人?[true]
16:02:33.685 [jack] DEBUG liheng - ------男女搭配干活不累;啪啪啪写完了代码
16:02:33.685 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:02:33.685 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:02:33.686 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:02:33.686 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:02:33.686 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:02:33.687 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:02:33.687 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:02:33.687 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:02:33.687 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:02:33.688 [其它人] DEBUG liheng - 我们10个屌丝工作了Process finished with exit code 0结果分析:jack比较牛逼,需要女人才能干活。jack线程拿到锁,看看是否有女人,没有女人false,没有女人等到五秒钟,这时别人也不能干活。主线程继续执行,这时候有女人了,桥本有菜来了。五秒到了jack再看了一下有没有女人,发现有女人了,然后开始敲代码干活。干完活之后,其他十个屌丝拿到锁,也干活了。*//**
上面代码如果打开注释
*/
for (int i = 0; i < 10; i++) {new Thread(() -> {synchronized (pc) {log.debug("我们10个屌丝工作了");}}, "其它人").start();
}
/**
-----------------------打印结果---------------------
16:22:27.726 [jack] DEBUG liheng - 有没有女人[false]
16:22:27.730 [jack] DEBUG liheng - 没有女人!等女人,等5秒;别人也不能干活
16:22:32.731 [jack] DEBUG liheng - 等了5秒 有没有女人?[false]
16:22:32.732 [jack] DEBUG liheng - ------下班回家----
16:22:32.732 [boss] DEBUG liheng - 桥本有菜来了
16:22:32.732 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:22:32.733 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:22:32.733 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:22:32.733 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:22:32.733 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:22:32.733 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:22:32.734 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:22:32.734 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:22:32.734 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:22:32.734 [其它人] DEBUG liheng - 我们10个屌丝工作了结果分析:jack比较牛逼,需要女人才能干活。jack线程拿到锁,看看是否有女人,没有女人false,没有女人等到五秒钟,这时别人也不能干活。主线程继续执行,这时候boss线程有女人但是它拿不到锁,给jack送不进去。等了5秒钟jack发现没有女人,下班回家了。这时候boss线程拿到了锁,将桥本有菜送了进去,释放锁,但是jack已经走了。其他十个屌丝拿到锁,开始干活。
*/

三、代码验证wait

场景1:多线程情况下,假设某个线程拿到锁了,但是它需要满足某个条件,才能执行,如果使用wait,会释放锁

@Slf4j(topic = "liheng")
public class TestWait2 {static final Object pc = new Object();static boolean isPrettyGril = false; // 女人public static void main(String[] args) throws InterruptedException {new Thread(() -> {synchronized (pc) {log.debug("有没有女人[{}]", isPrettyGril);if (!isPrettyGril) {log.debug("没有女人!等女人");try {pc.wait();} catch (InterruptedException e) {e.printStackTrace();}}log.debug("老板喊我了 有没有女人?[{}]", isPrettyGril);if (isPrettyGril) {log.debug("---男女搭配干活不累;啪啪啪写完了代码");}else{log.debug("下班回家");}}}, "jack").start();for (int i = 0; i < 10; i++) {new Thread(() -> {synchronized (pc) {log.debug( "我们10个屌丝工作了");}}, "其它人").start();}Thread.sleep(1000);new Thread(() -> {synchronized (pc) {isPrettyGril = true;log.debug("桥本有菜来了");pc.notify();}}, "boss").start();}
}
/**
------------------------打印结果-------------------
16:33:00.051 [jack] DEBUG liheng - 有没有女人[false]
16:33:00.054 [jack] DEBUG liheng - 没有女人!等女人
16:33:00.054 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:33:00.054 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:33:00.054 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:33:00.054 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:33:00.055 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:33:00.055 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:33:00.055 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:33:00.055 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:33:00.055 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:33:00.055 [其它人] DEBUG liheng - 我们10个屌丝工作了
16:33:01.051 [boss] DEBUG liheng - 桥本有菜来了
16:33:01.052 [jack] DEBUG liheng - 老板喊我了 有没有女人?[true]
16:33:01.052 [jack] DEBUG liheng - ---男女搭配干活不累;啪啪啪写完了代码结果分析:jack比较牛逼,需要女人才能干活。jack线程拿到锁,看看是否有女人,没有女人false,开始等待老板给分配女人(wait等待),释放了办公室的钥匙,其他是个屌丝拿到锁开始干活,干完活释放锁。老板线程拿到锁,带来了桥本有菜,把jack唤醒。jack看有没有女人,发现桥本有菜来了,开始干活敲代码。
*/

场景2: 多线程情况下,假设有多个线程执行需要满足某个条件,才能执行。(jack线程需要girl,rose线程需要money)

@Slf4j(topic = "liheng")
public class TestWait3 {static final Object pc = new Object();static boolean isPrettyGril = false; // 女人static boolean isMoney = false;//工资public static void main(String[] args) throws InterruptedException {new Thread(() -> {synchronized (pc) {log.debug("有没有女人[{}]", isPrettyGril);if (!isPrettyGril) {log.debug("没有女人!等女人");try {pc.wait();} catch (InterruptedException e) {e.printStackTrace();}}log.debug("老板喊我了 有没有女人?[{}]", isPrettyGril);if (isPrettyGril) {log.debug("男女搭配干活不累;啪啪啪写完了代码");}else {log.debug("不干了---下班回家--------");}}}, "jack").start();new Thread(() -> {synchronized (pc) {log.debug("有没有工资[{}]", isMoney);if (!isMoney) {log.debug("没有工资!等发工资");try {pc.wait();} catch (InterruptedException e) {e.printStackTrace();}}log.debug("老板喊我了 有没有发工资?[{}]", isMoney);if (isMoney) {log.debug("-----卧槽好多钱;啪啪啪写完了代码");}else {log.debug("约会去了");}}}, "rose").start();Thread.sleep(1000);new Thread(() -> {synchronized (pc) {isMoney = true;log.debug("发工资了---");pc.notify();}}, "boss").start();}
}
/**
--------------------结果打印-----------------
16:49:37.056 [jack] DEBUG liheng - 有没有女人[false]
16:49:37.058 [jack] DEBUG liheng - 没有女人!等女人
16:49:37.058 [rose] DEBUG liheng - 有没有工资[false]
16:49:37.059 [rose] DEBUG liheng - 没有工资!等发工资
16:49:38.057 [boss] DEBUG liheng - 发工资了---
16:49:38.058 [jack] DEBUG liheng - 老板喊我了 有没有女人?[false]
16:49:38.058 [jack] DEBUG liheng - 不干了---下班回家--------
结果分析:jack线程执行,看是否有女人,没有女人等等待女人(wait),rose线程执行,看有没有工资,没有工资没有工资等工资(wait),boss线程拿到锁,发了工资,随机唤醒了jack线程。jack看到没有女人,不干了下班回家。这时候rose线程还在等待被唤醒。问题1:notify随机唤醒了jack线程,但是boss线程带来了money,理论说执行rose线程才是对的。那是因为notify时随机唤醒的。问题1解决:使用notifyAll()唤醒,jack和roes线程都会被唤醒。打印结果如下:16:58:19.881 [jack] DEBUG liheng - 有没有女人[false]
16:58:19.883 [jack] DEBUG liheng - 没有女人!等女人
16:58:19.883 [rose] DEBUG liheng - 有没有工资[false]
16:58:19.883 [rose] DEBUG liheng - 没有工资!等发工资
16:58:20.881 [boss] DEBUG liheng - 发工资了---
16:58:20.881 [rose] DEBUG liheng - 老板喊我了 有没有发工资?[true]
16:58:20.881 [rose] DEBUG liheng - -----卧槽好多钱;啪啪啪写完了代码
16:58:20.881 [jack] DEBUG liheng - 老板喊我了 有没有女人?[false]
16:58:20.881 [jack] DEBUG liheng - 不干了---下班回家--------问题2:在使用notifyAll()唤醒的时候,jack和rose线程都被唤醒了,但是jack条件不满足,下班回家了,实际来说,jack应该一直等待有女人后敲完代码,才算正确。
*/

场景3:解决上面场景2中的的问题2

@Slf4j(topic = "liheng")
public class TestWait5 {static final Object pc = new Object();static boolean isPrettyGril = false; // 女人static boolean isMoney = false;//工资public static void main(String[] args) throws InterruptedException {new Thread(() -> {synchronized (pc) {log.debug("有没有女人[{}]", isPrettyGril);while (!isPrettyGril) {log.debug("没有女人!等女人");try {pc.wait();} catch (InterruptedException e) {e.printStackTrace();}}log.debug("老板喊我了 有没有女人?[{}]", isPrettyGril);if (isPrettyGril) {log.debug("男女搭配干活不累;啪啪啪写完了代码");}else {log.debug("不干了---下班回家--------");}}}, "jack").start();new Thread(() -> {synchronized (pc) {log.debug("有没有工资[{}]", isMoney);while (!isMoney) {log.debug("没有工资!等发工资");try {pc.wait();} catch (InterruptedException e) {e.printStackTrace();}}log.debug("老板喊我了 有没有发工资?[{}]", isMoney);if (isMoney) {log.debug("-----卧槽好多钱;啪啪啪写完了代码");}}}, "rose").start();Thread.sleep(1000);new Thread(() -> {synchronized (pc) {isMoney = true;log.debug("发工资了---");pc.notifyAll();}}, "boss").start();}
}
/**
------------------打印结果-----------------
17:03:48.605 [jack] DEBUG liheng - 有没有女人[false]
17:03:48.608 [jack] DEBUG liheng - 没有女人!等女人
17:03:48.608 [rose] DEBUG liheng - 有没有工资[false]
17:03:48.608 [rose] DEBUG liheng - 没有工资!等发工资
17:03:49.604 [boss] DEBUG liheng - 发工资了---
17:03:49.605 [rose] DEBUG liheng - 老板喊我了 有没有发工资?[true]
17:03:49.605 [rose] DEBUG liheng - -----卧槽好多钱;啪啪啪写完了代码
17:03:49.605 [jack] DEBUG liheng - 没有女人!等女人结果分析:使用了while死循环,解决问题2,jack线程一直在等待女人,并没有回家。
*/
notifyAll()的经典使用模
synchronized (lock) {while (condition) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}// todo 业务代码
}

并发编程-wait和sleep相关推荐

  1. Day 33 并发编程3

    目录 Day 33 并发编程3 生产者消费者模型 要解决什么问题 用途 多线程 什么是线程 进程对比线程 为什么用线程 使用线程 线程安全问题 守护线程 线程中的常用方法 Day 33 并发编程3 生 ...

  2. java线程钥匙_Java多线程并发编程/锁的理解

    一.前言 最近项目遇到多线程并发的情景(并发抢单&恢复库存并行),代码在正常情况下运行没有什么问题,在高并发压测下会出现:库存超发/总库存与sku库存对不上等各种问题. 在运用了 限流/加锁等 ...

  3. java虚拟机线程调优与底层原理分析_Java并发编程——多线程的底层原理

    " Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为汇编指令在CPU上执行,Java中所使用的并发机制依赖于JVM的实现和 CPU的 ...

  4. 并发编程之多进程编程(python版)

    目录 1 python多进程编程概述 2 需求和方案 背景: 需求: 解决思路: 需要解决的问题和方案: 3 完整代码 1 python多进程编程概述 python中的多线程无法利用多核优势,如果想要 ...

  5. 【收藏】Java多线程/并发编程大合集

    (一).[Java并发编程]并发编程大合集-兰亭风雨    [Java并发编程]实现多线程的两种方法    [Java并发编程]线程的中断    [Java并发编程]正确挂起.恢复.终止线程    [ ...

  6. JSR 133 Java内存模型以及并发编程的最权威论文汇总

    Java内存模型 先看官方文档: https://docs.oracle.com/javase/specs/ JSR 133:Java TM内存模型和线程规范修订版:https://www.jcp.o ...

  7. python并发编程方法_Python Futures并发编程详解

    无论哪门编程语言,并发编程都是一项很常用很重要的技巧.例如,爬虫就被广泛应用在工业界的各个领域,我们每天在各个网站.各个 App 上获取的新闻信息,很大一部分便是通过并发编程版的爬虫获得. 正确合理地 ...

  8. Python3 与 C# 并发编程之~ Net篇

    NetCore并发编程 示例代码:https://github.com/lotapp/BaseCode/tree/master/netcore/4_Concurrency 先简单说下概念(其实之前也有 ...

  9. java 并发统计_java并发编程|CountDownLatch计数器

    0x01,CountDownLatch介绍 CountDownLatch是一个计数器,作为java并发编程中三个组件之一,这个组件的使用频率还是很多的.这里分享下自己画的java并发编程组件的图,后面 ...

  10. Java并发编程71道面试题及答案

    Java并发编程71道面试题及答案 1.在java中守护线程和本地线程区别? java中的线程分为两种:守护线程(Daemon)和用户线程(User). 任何线程都可以设置为守护线程和用户线程,通过方 ...

最新文章

  1. bootsrap学习
  2. Markdown 语法介绍
  3. assert()函数用法
  4. java头像选择系统_Android+超高仿微信图片选择器(头像选择)
  5. 百度api语音识别一直“无内容”_PHP开发语音识别功能
  6. linux chromebook arm,第一款可拆卸 ARM Chromebook 可能是 KODAMA
  7. Java作业-多线程
  8. 一文搞定数据结构(图解)
  9. 1020 月饼 (25 分)—PAT (Basic Level) Practice (中文)
  10. FR多sheet的内置检验和JS校验, 数据集范围校验;填报存在时不提交并提示已存在
  11. Matlab 遗传算法gaot、gatbx工具箱安装(出现未找到 ‘initializega‘、‘crtbp‘等错误)
  12. springboot使用yml格式报错
  13. 苹果电脑安装windows系统 失败后 磁盘空间丢失
  14. hadoop(二)-hadoop原理及架构
  15. Fisher exact test费雪精确检验
  16. PS2022免安装绿色版
  17. govqq.com/post/12.html,更新30+!这些学校招生简章已公布!
  18. Java————错误:找不到或无法加载主类
  19. 360高级前端架构师Hax(贺师俊):前端开发编程语言的过去、现在和未来
  20. java 导出复杂格式的 Excel 留着自己备用

热门文章

  1. 做好外汇资金管理 高效的发挥资金的作用
  2. 关于Excel文件导入
  3. 2023远程控制软件排行榜
  4. 傅立叶变换与小波变换
  5. Windows Server 2012 R2双网卡配置
  6. FFmpeg常用命令流媒体命令
  7. 百度地图可视化之实现散点图
  8. Amlogic平台固定摄像头facing办法
  9. css 写一个向右的箭头
  10. javaScript实现顶部通栏:往下滑动到距离顶部一定距离,顶部通栏消失;再往上滑动到距离顶部一定距离,顶部通栏再次出现;滚动条往上滑动也会出现(注意CSS样式中的渐变设置)