wait 加锁示例

public class WaitDemo {private static Object locker = new Object();public static void main(String[] args) throws InterruptedException {WaitDemo waitDemo = new WaitDemo();// 启动新线程,防止主线程被休眠new Thread(() -> {try {waitDemo.doWait();} catch (InterruptedException e) {e.printStackTrace();}}).start();Thread.sleep(200); // 此行本身没有意义,是为了确保 wait() 先执行再执行 notify()waitDemo.doNotify();}/*** 执行 wait()*/private void doWait() throws InterruptedException {synchronized (locker) {System.out.println("wait start.");locker.wait();System.out.println("wait end.");}}/*** 执行 notify()*/private void doNotify() {synchronized (locker) {System.out.println("notify start.");locker.notify();System.out.println("notify end.");}}
}

以上程序的执行结果为:

wait start.

notify start.

notify end.

wait end.

代码解析

从上述代码可以看出,我们给 wait() 和 notify() 两个方法上了同一把锁(locker),但在调用完 wait() 方法之后 locker 锁就被释放了,所以程序才能正常执行 notify() 的代码,因为是同一把锁,如果不释放锁的话,是不会执行 notify() 的代码的,这一点也可以从打印的结果中证实(结果输出顺序),所以综合以上情况来说 wait() 方法是释放锁的

sleep 加锁示例

public class WaitDemo {private static Object locker = new Object();public static void main(String[] args) throws InterruptedException {WaitDemo waitDemo = new WaitDemo();// 启动新线程,防止主线程被休眠new Thread(() -> {synchronized (locker) {try {System.out.println("sleep start.");Thread.sleep(1000);System.out.println("sleep end.");} catch (InterruptedException e) {e.printStackTrace();}}}).start();Thread.sleep(200);waitDemo.doNotify();}/*** 执行 notify()*/private void doNotify() {synchronized (locker) {System.out.println("notify start.");locker.notify();System.out.println("notify end.");}}
}

以上程序的执行结果为:

sleep start.

sleep end.

notify start.

notify end.

代码解析

从上述代码可以看出 sleep(1000) 方法(行号:11)执行之后,调用 notify() 方法并没有获取到 locker 锁,从上述执行结果中可以看出,而是执行完 sleep(1000) 方法之后才执行的 notify() 方法,因此可以证明调用 sleep() 方法并不会释放锁

知识扩展

1.sleep 和 wait 有什么区别?

sleepwait 几乎是所有面试中必问的题,但想完全回答正确似乎没那么简单。

对于 sleepwait 的区别,通常的回答是这样的:

  • wait 必须搭配 synchronize 一起使用,而 sleep 不需要;

  • 进入 wait 状态的线程能够被 notify 和 notifyAll 线程唤醒,而 sleep 状态的线程不能被 notify 方法唤醒;

  • wait 通常有条件地执行,线程会一直处于 wait 状态,直到某个条件变为真,但是 sleep 仅仅让你的线程进入睡眠状态;

  • wait 方法会释放对象锁,但 sleep 方法不会。

但上面的回答显然遗漏了一个重要的区别,在调用 wait 方法之后,线程会变为 WATING 状态,而调用 sleep 方法之后,线程会变为 TIMED_WAITING 状态。

2.wait 能不能在 static 方法中使用?为什么?

不能,因为 wait 方法是实例方法(非 static 方法),因此不能在 static 中使用,源码如下:

public final void wait() throws InterruptedException {wait(0);
}

3.wait/notify 可以不搭配 synchronized 使用吗?为什么?

不行,因为不搭配 synchronized 使用的话程序会报错,如下图所示:

更深层次的原因是因为不加 synchronized 的话会造成 Lost Wake-Up Problem,唤醒丢失的问题,详情可见:https://juejin.im/post/5e6a4d8a6fb9a07cd80f36d1

总结

本文我们通过 synchronized 锁定同一对象,来测试 wait 和 sleep 方法,再通过执行结果的先后顺序证明:wait 方法会释放锁,而 sleep 方法并不会。同时我们还讲了几个 waitsleep 的常见面试问题,希望本文可以帮助到你。

漫画:Integer 竟然有 4 种比较方法?

漫画:对象是如何被找到的?句柄 OR 直接指针?

关注下方二维码,每一天都有干货!

漫画:如何证明sleep不释放锁,而wait释放锁?相关推荐

  1. 并发系列三:证明分代年龄、无锁、偏向锁、轻量锁、重(chong)偏向、重(chong)轻量、重量锁

    前言 上篇文章咱们了解了synchronized关键字的常见用法.对象头以及证明了一个对象在无锁状态下的对象头markwork部分的前56位存储的是hashcode.接下来,咱们继续来根据对象头分别证 ...

  2. JAVA偏向锁的什么时候释放_Java中的偏向锁

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 Java偏向锁(Biased Locking)是Java6引入的一项多线程优化. 偏向锁,顾名思义,它会偏向于第一个访问锁的线程,如果在运行过程中,同步锁 ...

  3. 6※、线程同步、同步锁、同步代码块的使用、同步锁释放的时机、ReentrantLock可重入锁、公平锁与非公平锁的区别、什么是死锁、线程间的通信(生产者和消费者模式)

    线程锁 1.※线程的同步:(要确保对象锁是一致的) 1.未使用同步锁的抢票 2.使用了同步锁的抢票 3.线程-同步代码块的使用 4.同步方法和代码块的区别 5.同步锁释放的时机 练习:多线程生产手机 ...

  4. 死锁终结者:顺序锁和轮询锁!

    作者 | 王磊 来源 | Java中文社群(ID:javacn666) 转载请联系授权(微信ID:GG_Stone 死锁(Dead Lock)指的是两个或两个以上的运算单元(进程.线程或协程),都在等 ...

  5. 【高并发】高并发分布式锁架构解密,不是所有的锁都是分布式锁!!

    来自:冰河技术 写在前面 最近,很多小伙伴留言说,在学习高并发编程时,不太明白分布式锁是用来解决什么问题的,还有不少小伙伴甚至连分布式锁是什么都不太明白.明明在生产环境上使用了自己开发的分布式锁,为什 ...

  6. 1.6的锁优化(适应性自旋/锁粗化/锁削除/轻量级锁/偏向锁)

    高效并发是JDK 1.6的一个重要主题,HotSpot虚拟机开发团队在这个版本上花费了大量的精力去实现各种锁优化技术,如适应性自旋(Adaptive Spinning).锁削除(Lock Elimin ...

  7. 锁优化:逃逸分析、自旋锁、锁消除、锁粗化、轻量级锁和偏向锁

    1. 逃逸分析 Escape Analysis 1.1 逃逸分为两种: 方法逃逸:当一个对象在方法中被定义后,可能作为调用参数被外部方法说引用. 线程逃逸:通过复制给类变量或者作为实例变量在其他线程中 ...

  8. 多线程:无锁、偏向锁、轻量锁、重量级锁

    一:java多线程互斥,和java多线程引入偏向锁和轻量级锁的原因? --->synchronized的重量级别的锁,就是在线程运行到该代码块的时候,让程序的运行级别从用户态切换到内核态,把所有 ...

  9. Java面试之锁-可重入锁和递归锁

    可重入锁和递归锁ReentrantLock 概念 可重入锁就是递归锁 指的是同一线程外层函数获得锁之后,内层递归函数仍然能获取到该锁的代码. 在同一线程在外层方法获取锁的时候,在进入内层方法会自动获取 ...

  10. postgresql 索引状态_PostgreSQL中的锁:3.其他锁

    我们已经讨论了一些对象级锁(特别是关系级锁),以及行级锁及其与对象级锁的连接,还探讨了等待队列.这次我们要来个大杂烩.我们将从死锁开始(实际上,我计划上次讨论死锁,但是这篇文章本身篇幅太长了),然后简 ...

最新文章

  1. 看完这些细分领域别说小程序代理创业没有机会
  2. Eclipse开发struts完全指南
  3. 皮一皮:中国男足啊..这球少一个人帮忙这球都进不了...
  4. Android Service的思考(1)
  5. 利用套接字实现 CS 模型
  6. js 方法传递对象参数
  7. BOM(Browser Object Model)
  8. 数据分析专题报告范文6篇_小学生看图写话范文:小熊玩跷跷板?(6篇),让孩子参考练习...
  9. 有感于去哪儿的一道笔试题
  10. TopFreeTheme精选免费模板【20130703】
  11. HOLOLENS的DEVICE POTAL连接和安装
  12. 索尼计算机bios正确设置,索尼vaio笔记本如何进入bios设置_索尼笔记本进入bios图解...
  13. 大数据导论2之大数据与云计算、物联网、人工智能
  14. 动态inventory
  15. windows2012取消自动ipv4_Win10删除自动配置ipv4|Win10自动配置ip地址怎么关闭
  16. java bufferedimage 内存溢出_大图片内存溢出问题!!!
  17. 清华大学邓俊辉《数据结构(C++语言版)第3版》随书资源
  18. 微信小程序 界面从右边滑出_微信小程序--左滑右滑的乐趣
  19. 数据结构— —单链表
  20. mysql 视图报错1356,mysql视图初探 - osc_ky6f5kf1的个人空间 - OSCHINA - 中文开源技术交流社区...

热门文章

  1. Oracle GoldenGate经典架构
  2. CentOS 5打造全功能Web服务器
  3. git 命令 clone分支的代码
  4. 【原创】利用腾讯和百度的AI接口识别验证码
  5. VDI序曲二 RemotoAPP部署
  6. MongoDB: The Definitive Guide
  7. head first python(第三章)–学习笔记
  8. 创建oracle 数据库表空间,角色,用户的sql语句
  9. (转)解读NTFS(一)
  10. python类的编写模板_python开发笔记-类