干货-并发编程提高——线程的唤醒(七)

  1. 没有参数的wait()方法等价于wait(0),等价于永远等下去。

  2. 虚假唤醒 :一个线程也能在没有被通知,中断,或超时的情况下被唤醒。也即所谓的"虚假唤醒"。

  3. 解决虚假唤醒的办法就是通过while循环来判断条件。

  4. 何为虚假唤醒

  5. 简单讲,要避免使用 if 的方式来判断条件,否则一旦线程恢复,就继续往下执行,不会再次检测条件。由于可能存在的"虚假唤醒",并不意味着条件是满足的,这点甚至对简单的"二人转"的两个线程的 wait/notify 情况也需要注意。

  6. 另外,如果对于更多线程的情况,比如"生产者和消费者"问题,一个生产者,两个消费者,更加不能简单用 if 判断。因为可能用的是 notifyAll,两个消费者同时起来,其中一个先抢到了锁,进行了消费,等另一个也抢到锁时,可能条件又不满足了,所以还是要继续判断,不能简单认为被唤醒了就是条件满足了。不过,这是一个不确定的等待,可能等待(无法获取锁时),也可能不等待(能获取锁)。陷入这种阻塞后也没有自主退出的机制。

  7. BLOCKED 和 WAITING 状态的区别和联系

  8. 在说完了 BLOCKED,WAITING 和 TIMED_WAITING 后,我们可以综合来看看它们,比如,阻塞与等待到底有什么本质的区别呢?

  9. 显然,BLOCKED 同样可以视作是一种特殊的,隐式的 wait/nofity 机制。等待的条件就是"有锁还是没锁"。

  10. 有一点需要注意的是,BLOCKED 状态是与 Java 语言级别的 synchronized 机制相关的,我们知道在 Java 5.0 之后引入了更多的机制(java.util.concurrent),除了可以用 synchronized 这种内部锁,也可以使用外部的显式锁。

  11. 显式锁有一些更好的特性,如能中断,能设置获取锁的超时,能够有多个条件等,尽管从表面上说,当显式锁无法获取时,我们还是会说,线程被"阻塞"了,但却未必是 BLOCKED 状态。

  12. 当锁可用时,其中的一个线程会被系统隐式通知,并被赋予锁,从而获得在同步块中的执行权。

  13. 显然,等待锁的线程与系统同步机制形成了一个协作关系。

  14. 对比来看, WAITING 状态属于主动地显式地申请的阻塞,BLOCKED 则属于被动的阻塞,但无论从字面意义还是从根本上来看,并无本质的区别。

  15. 在前面我们也已经说过,这三个状态可以认为是传统 waiting 状态在 JVM 层面的一个细分。

  16. 主流java虚拟机的实现中,java线程是映射到操作系统的元素内核线程之上的。Java线程->LWP(轻量级进程)->KLT(内核级线程),如果要阻塞或唤醒一条线程。则需要操作系统来帮忙完成。这样就不可避免的会陷入用用户态到核心态的转换之中。状态转换是很耗费处理器时间的。虚拟机本身也会进行一些优化,诸如在进入阻塞前,加入一段自旋等待过程。以避免频繁切换。

相关推荐
RainbowSea9 小时前
12. LangChain4j + 向量数据库操作详细说明
java·langchain·ai编程
RainbowSea9 小时前
11. LangChain4j + Tools(Function Calling)的使用详细说明
java·langchain·ai编程
考虑考虑13 小时前
Jpa使用union all
java·spring boot·后端
用户37215742613513 小时前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊14 小时前
Java学习第22天 - 云原生与容器化
java
渣哥16 小时前
原来 Java 里线程安全集合有这么多种
java
间彧16 小时前
Spring Boot集成Spring Security完整指南
java
间彧17 小时前
Spring Secutiy基本原理及工作流程
java
Java水解18 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
洛小豆20 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试