为什么wait 和notifyAll 必须要使用synchronized?

    为什么wait 和notifyAll(notify) 必须要使用synchronized?

synchronized(object){
   object.wait();
}

 

synchronized(this){
   this.wait();
}

 

synchronized fun(){
    this.wait();
}

  

    如果不用在synchronized里面就会报错:

java.lang.IllegalMonitorStateException

       首先明确wait 和notifyAll是基于对象而存在的。wait等待的就是一个对象发出的信号。

       既然基于对象,因此需要一个数据结构来存放这些等待的线程,而且这个数据结构应当与这个对象绑定,此时在这个对象上面可能有多个线程调用wait/notifyAll方法。

       在向这个数据结构上面写入,删除数据时,依然存在并发问题,理论上也需要一个锁来控制。在JVM中是通过检查当前线程是否为对象的OWNER来判定是否要抛出相应的异常,由此可见他希望该动作由Java程序抽象层来控制。

 

 

在 Java 中,`notify()` `notifyAll()` 是两个重要的线程同步方法,用于在线程间实现通信机制。以下是关于这两个方法的具体区别及其用法: ### 1. 方法定义与作用 #### notify() - **功能**: 只唤醒一个处于等待状态的线程(如果有多个线程都在等待,则由 JVM 决定具体唤醒哪一个)[^4]。 - **适用场景**: 当仅有一个线程需要被唤醒时,或者并不关心哪个具体的线程会被唤醒的情况下可以使用此方法。 #### notifyAll() - **功能**: 唤醒所有正在等待同一个对象锁的线程。这些线程随后会进入锁的竞争阶段,只有获得锁的那个线程才能继续运行。 - **适用场景**: 如果有多个线程都需要被通知并重新评估其条件变量的状态,则应选用 `notifyAll()` 来确保不会遗漏任何应该被处理的任务。 ### 2. 主要区别 | 特性 | notify() | notifyAll() | |---------------------|---------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------| | **唤醒线程数量** | 只唤醒单个线程 | 唤醒所有等待中的线程 | | **资源竞争程度** | 较低;因为只激活了一个线程 | 高度增;由于所有的线程都被激活并将尝试获取同一把锁 | | **典型应用场景** | 单一线程依赖于特定事件完成工作 | 多个独立工作的线程均需知晓某共享数据已发生变化 | 需要注意的是,在某些情况下错误地选择了其中之一可能会引发问题比如死锁或饥饿现象。例如当调用了`notify()`却期望另一个未被选中的线程能够响应的时候就可能出现此类情况。 ### 3. 示例代码展示两者差异 假设我们有两个消费者线程ConsumerAConsumerB以及生产者Producer,他们共同操作堆栈Stack: ```java public class Stack { private int[] elements; private int size; public synchronized void push(int element){ while(size == elements.length){ try{ wait(); // If stack is full, producer waits. }catch(InterruptedException e){} } elements[size++] = element; System.out.println("Pushed "+element); notify(); } public synchronized int pop(){ while (size==0){ try{ wait();//If empty , consumer should wait until notified by a producer adding an item to the queue. } catch(InterruptedException ex){} } int result=elements[--size]; System.out.println("Popped "+result); notifyAll(); // Notify all waiting threads that state has changed. return result; } } ``` 在这个例子中,如果我们仅仅使用了`notify()`而不是`notifyAll()`的话,那么有可能会出现这样的状况——即其中一个消费线程已经准备好去消耗新的项目但由于之前那个已经被唤醒过的消费线程仍然持有锁而导致它无法立即执行自己的任务从而造成不必要的延迟甚至潜在的逻辑错误。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值