写点什么

你真的知道 Java 同步锁何时释放?

  • 2022 年 5 月 14 日
  • 本文字数:1289 字

    阅读完需:约 4 分钟

其他答案:


wait 中的线程是不会去竞争对象锁的。 据我所知,开始由于调用了对象的 wait 方法,线程处于该对象的等待池中,


而后,只有再去调用对象的 notifyAll()(唤醒所有等待池中的线程)或者 notify()(随机唤醒线程,姑且假设唤醒了我们的那个线程),线程会进入该对象的锁池之中。


锁池中的对象相互竞争对象锁,优先级高的线程竞争得到对象锁的概率高,假若线程没有竞争到,它还是会在锁池之中,唯有线程再次调用 wait 方法,它才会重新回到等待池中。


[](()java 多线程什么时候释放锁—wait()、notify()




由于等待一个锁定线程只有在获得这把锁之后,才能恢复运行,所以让持有锁的线程在不需要锁的时候及时释放锁是很重要的。在以下情况下,持有锁的线程会释放锁:


  • 执行完同步代码块。

  • 在执行同步代码块的过程中,遇到异常而导致线程终止。

  • 在执行同步代码块的过程中,执行了锁所属对象的 wait()方法,这个线程会释放锁,进行对象的等待池。


除了以上情况外,只要持有锁的此案吃还没有执行完同步代码块,就不会释放锁。因此在以下情况下,线程不会释放锁:


  1. 在执行同步代码块的过程中,执行了 Thread.sleep()方法,当前线程放弃 CPU,开始睡眠,在睡眠中不会释放锁。

  2. 在执行同步代码块的过程中,执行了 Thread.yield()方法,当前线程放弃 CPU,但不会释放锁。

  3. 在执行同步代码块的过程中,其他线程执行了当前对象的 suspend()方法,当前线程被暂停,但不会释放锁。但 Thread 类的 suspend()方法已经被废弃。


避免死锁的一个通用的经验法则是:当几个线程都要访问共享资源 A、B 和 C 时,保证使每个线程都按照同样的顺序去访问他们,比如都先访问 A,再访问 B 和 C。


  • java.lang.Object 类中提供了两个用于线程通信的方法:wait()和 notify()。需要注意到是,wait()方法必须放在一个循环中,因为在多线程环境中,共享对象的状态随时可能改变。当一个在对象等待池中的线程被唤醒后,并不一定立即恢复运行,等到这个线程获得了锁及 CPU 才能继续运行,又可能此时对象的状态已经发生了变化。

  • 调用 obj 的 wait(), notify()方法前,必须获得 obj 锁,也就是必须写在 synchronized(obj) {…} 代码段内。


# 调用 obj.wait()后,线程 A 就释放了 obj 的锁,否则线程 B 无法获得 obj 锁,也就无法在 synchronized(obj) {…} 代码段内唤醒 A。


# 当 obj.wait()方法返回后,线程 A 需要再次获得 obj 锁,才能继续执行。


# 如果 A1,A2,A3 都在 obj.wait(),则 B 调用 obj.notify()只能唤醒 A1,A2,A3 中的一个(具体哪一个由 JVM 决定)。


# obj.notifyAll()则能全部唤醒 A1,A2,A3,但是要继续执行 obj.wait()的下一条语句,必须获得 obj 锁,因此,A1,A2,A3 只有一个有机会获得锁继续执行,例如 A1,其余的需要等待 A1 释放 obj 锁之后才能继续执行。


# 当 B 调用 obj.notify/notifyAll 的时候,B 正持有 obj 锁,因此,A1,A2,A3 虽被唤醒,但是仍无法获得 obj 锁。直到 B 退出 synchronized 块,释放 obj 锁后,A1,A2,A3 中的一个才有机会获得锁继续执行。


[](()wait()/sleep()的区别


------ 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 ------------------------------------------------------------------------

用户头像

还未添加个人签名 2022.04.13 加入

还未添加个人简介

评论

发布
暂无评论
你真的知道Java同步锁何时释放?_Java_爱好编程进阶_InfoQ写作社区