Java 有等待/通知和无等待/通知的同步块之间的差异?

Java 有等待/通知和无等待/通知的同步块之间的差异?,java,multithreading,wait,synchronized,notify,Java,Multithreading,Wait,Synchronized,Notify,如果我只使用synchronized,而不是wait/notify方法,它仍然是线程安全的吗 有什么区别吗?使用synchronized使得一次只能在线程上访问方法/块。所以,是的,它是线程安全的 这两个概念是结合在一起的,不是相互排斥的。使用wait()时,您需要拥有该对象上的监视器。因此,在此之前,您需要对其进行同步(..)。使用.wait()使当前线程停止,直到另一个线程对其等待的对象调用.notify()。这是对synchronized的一个补充,它只确保只有一个线程将进入一个块/方法。

如果我只使用
synchronized
,而不是
wait
/
notify
方法,它仍然是线程安全的吗


有什么区别吗?

使用
synchronized
使得一次只能在线程上访问方法/块。所以,是的,它是线程安全的

这两个概念是结合在一起的,不是相互排斥的。使用
wait()
时,您需要拥有该对象上的监视器。因此,在此之前,您需要对其进行
同步(..)
。使用
.wait()
使当前线程停止,直到另一个线程对其等待的对象调用
.notify()
。这是对
synchronized
的一个补充,它只确保只有一个线程将进入一个块/方法。

有效的Java第69项:“考虑到使用wait和 如果通知正确,则应改用更高级别的并发实用程序。“


避免使用wait()和notify():尽可能使用
synchronized
,或来自的其他实用程序。

因此,在一个关于这个问题的采访中感到尴尬之后,我决定再次查找并理解它10亿次

synchronized
块使代码线程安全。毫无疑问。当
wait()
notify()
notifyAll()
进入时,您正试图编写更高效的代码。例如,如果您有一个多线程共享的项目列表,那么如果您将它放在监视器的
synchronized
块中,那么线程将不断跳入并在上下文切换期间来回运行代码……即使列表为空

因此,监视器(synchronized(..)中的对象)上使用wait()作为一种机制,通知所有线程停止使用cpu周期,直到进一步通知或notifyAll()

比如:

已同步(监视器){
if(list.isEmpty())
monitor.wait();
}
…在别的地方

已同步(监视器){
列表。添加(内容);
monitor.notifyAll();
}

如果“同一对象”的两个线程试图获取锁,则使用同步块。因为对象类持有锁,所以它知道给谁。 然而,如果两个对象(obj1的t1和t2以及obj2的t3和t4)的两个线程(比如t2和t4)尝试获取锁,obj1将不知道obj2的锁,而obj2将不知道obj1的锁。因此使用了wait和notify方法

例如:

//java同步方法的示例
类表{
同步的void打印表(int n){//synchronized方法

for(int i=1;iwait/notify)是在同步块内等待某些条件(如用户输入)时需要的

典型用法:

synchronized(obj) {
    // do something

    while(some condition is not met) {
        obj.wait();
    }
    // do something other
}
假设不使用wait(),则必须实现所需的忙循环轮询条件,这对性能不利

synchronized(obj) {
    // do something

    while(some condition is not met) { // busy loop }

    // do something other
}
重要提示:即使线程被notify()或notifyAll()唤醒从其他线程,唤醒线程不保证立即恢复其执行。如果有其他线程等待在同一对象上执行同步块,则唤醒线程应与线程竞争。

使方法as具有两种效果:

首先,同一对象上的两个同步方法调用不可能交错进行。当一个线程为一个对象执行同步方法时,所有为同一对象块调用同步方法的其他线程(暂停执行),直到第一个线程处理完该对象

其次,当同步方法退出时,它会自动与同一对象的同步方法的任何后续调用建立“发生在之前”关系。这保证了对象状态的更改对所有线程都是可见的

同步可以帮助您保护关键代码

如果要在多个线程之间建立通信,必须使用和/

wait()
:使当前线程等待,直到另一个线程调用此对象的notify()方法或notifyAll()方法

notify()
:唤醒正在等待此对象监视器的单个线程。如果有任何线程正在等待此对象,则选择其中一个线程进行唤醒

notifyAll()
:唤醒在此对象监视器上等待的所有线程。线程通过调用其中一个等待方法在对象监视器上等待

使用wait()和notify()的简单用例:生产者和消费者问题

消费者线程必须等待生产者线程生成数据。wait()和notify()在上述场景中非常有用。经过一段时间,已经引入了更好的替代方案。请参阅本教程页面

简单来说:

使用
synchronized
保护数据的关键部分并保护代码

如果您希望以安全的方式在相互依赖的多个线程之间建立通信,请在同步的同时使用
wait()
notify()

相关SE问题:


那么为什么我们需要使用wait/notify方法呢?肯定有一些不同,对吧?我认为当同步块结束时,它会释放锁。其他执行同步方法或语句的线程在无法获得锁时会阻塞。它的行为也类似于wait()notify()机制,非常相似。Alan在问,使用wait()和notify()与普通的同步块结束有什么区别。它规定您总是在循环内调用wait(),例如while(list.isEmpty())monitor.wait()如果您想等待,直到另一个线程实际将某个内容放入列表中。这应该是答案。程序员不能选择哪个同步块应该首先进入。B
synchronized(obj) {
    // do something

    while(some condition is not met) {
        obj.wait();
    }
    // do something other
}
synchronized(obj) {
    // do something

    while(some condition is not met) { // busy loop }

    // do something other
}