V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
linxiaoziruo
V2EX  ›  Java

Java 多线程问题

  •  
  •   linxiaoziruo · 2020-05-30 15:46:29 +08:00 · 2799 次点击
    这是一个创建于 1668 天前的主题,其中的信息可能已经有所发展或是发生改变。

    为什么使用 notify 和 notifyAll 的时候要先获得锁?

    13 条回复    2020-06-01 11:33:58 +08:00
    cs419
        1
    cs419  
       2020-05-30 17:19:43 +08:00
    没这个说法 不搭嘎

    你想想
    1. 为啥要用锁,不用锁会出啥问题 (原子性)
    2. 面对这个问题 怎么用 notify 去解决 (线程等待)

    如果确实要线程等待
    一般不用 notify 用 LockSupport
    linxiaoziruo
        2
    linxiaoziruo  
    OP
       2020-05-30 19:35:11 +08:00
    @cs419 怎么会不搭嘎呢,使用 notify 和 notifyAll 的时候必须要在 syncnorize 的临界区内,即必须先获得这个对象锁才能执行 notify,否则会抛出 IllegalMonitorStateException
    linxiaoziruo
        3
    linxiaoziruo  
    OP
       2020-05-30 19:38:58 +08:00
    @cs419 锁是解决共享资源竞争引起的线程安全问题,和原子性有什么关联呢,原子性指的是不能中断的操作,和锁是两个没有关联的概念。
    23571113
        4
    23571113  
       2020-05-30 20:25:49 +08:00
    notify 就是通知释放锁啊, 你没锁怎么释放.
    pursuer
        5
    pursuer  
       2020-05-30 20:27:30 +08:00
    notify,wait,和条件判断通常是一起用的,条件判断后选择进入等待或继续运行,这个时候要保证条件判断后,条件不会被其他线程改变,所以通常都会有个锁保障类似的场景。
    sioncheng
        6
    sioncheng  
       2020-05-30 21:50:39 +08:00
    notify \ wait 是一种协作吧,双方需要能获得相同的锁才能说明是是在协作干一个事情,要不然,不相干的参与者瞎 notify 能行吗
    lux182
        7
    lux182  
       2020-05-30 23:57:01 +08:00
    释放 monitor
    唤醒等待队列的线程
    seki4713
        8
    seki4713  
       2020-05-31 14:23:47 +08:00 via iPhone
    防止你条件判断成功后突然被抢占 然后条件被修改 保证判断条件到进入临界区的整个操作是原子的
    bigbyto
        9
    bigbyto  
       2020-05-31 20:48:34 +08:00
    这个问题其实真不好回答,就像大家习以为常的问题,突然被问为什么了。其实上面的老哥都没回答到点上,我觉得为什么 notify 必须要 synchorized,根本原因在于 wait set 的操作是原子的。先看看 JLS 对 wait set 的描述。

    > Every object, in addition to having an associated monitor, has an associated *wait set*. A wait set is a set of threads.
    >
    > When an object is first created, its wait set is empty. **Elementary actions that add threads to and remove threads from wait sets are atomic**. Wait sets are manipulated solely through the methods `Object.wait`, `Object.notify`, and `Object.notifyAll`.
    >
    > Ref: https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html

    简单来说,当对象创建时,会顺带创建 Monitor 和 Wait Set,这些应该是在 C 语言层面去创建的。然后它告诉我们对 Wait Set 的操作都是 Atomic 的,这就能解释,为什么 wait 和 notify 必须获得锁,因为没有锁,就没办法保证对 wait set 的操作是原子的。
    JasonLaw
        10
    JasonLaw  
       2020-06-01 08:19:03 +08:00 via iPhone
    来自 Java Concurrency in Practice 。

    Just as each Java object can act as a lock, each object can also act as a condition queue, and the wait, notify, and notifyAll methods in Object constitute the API for intrinsic condition queues. An object’s intrinsic lock and its intrinsic condition queue are related: in order to call any of the condition queue methods on object X, you must hold the lock on X. This is because the mechanism for waiting for state-based conditions is necessarily tightly bound to the mechanism for preserving state consistency: you cannot wait for a condition unless you can examine the state, and you cannot release another thread from a condition wait unless you can modify the state.

    Object.wait atomically releases the lock and asks the OS to suspend the current thread, allowing other threads to acquire the lock and therefore modify the object state. Upon waking, it reacquires the lock before returning. Intuitively, calling wait means “I want to go to sleep, but wake me when something interesting happens”, and calling the notification methods means “something interesting happened”.
    willxiang
        11
    willxiang  
       2020-06-01 09:14:46 +08:00
    "必须在 synchronized 块中才能调用 wait()方法,因为 wait()方法调用时,会释放线程获得的锁,wait()方法返回后,线程又会重新试图获得锁。"

    https://www.liaoxuefeng.com/wiki/1252599548343744/1306580911915042
    cs419
        12
    cs419  
       2020-06-01 10:28:56 +08:00
    忽然发现被降权了 没收到消息通知
    奇怪的知识增加了
    没觉着 wait 好用
    平时要么普通的多线程 要么 LockSupport 要么 JUC
    Kamiyu0087
        13
    Kamiyu0087  
       2020-06-01 11:33:58 +08:00
    直接从实际使用的情况来看的话,你如果 notify 的时候不去获得锁的话,没法保证 notify 在 wait 之后再执行啊
    ```java
    final Object lock = new Object();
    synchronized (lock) {
    new Thread(() -> lock.notify()).start();

    try {
    lock.wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    ```
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1803 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 16:20 · PVG 00:20 · LAX 08:20 · JFK 11:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.