java 带等待/通知和不带它们的同步块之间的区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7842265/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 21:39:47  来源:igfitidea点击:

Difference between Synchronized block with wait/notify and without them?

javamultithreadingwaitsynchronizednotify

提问by Alan

If I just use synchronized, not wait/notify method, will it still keep thread-safe ?

如果我只使用同步方法,而不是等待/通知方法,它还会保持线程安全吗?

What's the difference ?

有什么不同 ?

Thx in advance.

提前谢谢。

采纳答案by Bozho

Using synchronizedmakes a method / block accessible by only on thread at a time. So, yes, it's thread-safe.

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

The two concepts are combined, not mutually-exclusive. When you use wait()you need to own the monitor on that object. So you need to have synchronized(..)on it before that. Using .wait()makes the current thread stop until another thread calls .notify()on the object it waits on. This is an addition to synchronized, which just ensures that only one thread will enter a block/method.

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

回答by Arash Sharif

So after just being embarrassed in an interview question on this I decided to look it up and understand it again for 1 billionth time.

所以刚刚在面试问题上尴尬之后,我决定再查一遍,第 10 亿次再理解一遍。

synchronizedblock makes the code thread safe. No doubt about that. When wait()and notify()or notifyAll()come in is where you are trying to write more efficient code. For example, if you have a list of items that multiple threads share then if u put it in synchronizedblock of a monitor then threads threads will constantly jump in and run the code back and forth, back and forth during context switches......even with an empty list!

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

The wait() is hence used on the monitor (the object inside the synchronized(..)) as a mechanism to to tell all threads to chill out and stop using cpu cycles until further notice or notifyAll().

因此,wait() 用于监视器(synchronized(..) 中的对象)作为一种机制,告诉所有线程冷静下来并停止使用 CPU 周期,直到进一步通知或 notifyAll()。

so something like:

所以像:

synchronized(monitor) {
    if( list.isEmpty() )
        monitor.wait();
}

...somewhere else...

...别的地方...

synchronized(monitor){
    list.add(stuff);
    monitor.notifyAll();
}

回答by Ravindra babu

Making method as synchronizedhas two effects:

同步方法 有两个作用:

First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object

首先,对同一对象的同步方法的两次调用不可能交错。当一个线程正在为一个对象执行同步方法时,所有其他调用同一个对象的同步方法的线程都会阻塞(挂起执行),直到第一个线程完成对对象的处理

Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.

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

synchronization help you to guard the critical code.

同步帮助您保护关键代码。

If you want to establish communication between multiple threads, you have to use wait()and notify()/notifyAll()

如果要在多个线程之间建立通信,必须使用wait()notify()/ notifyAll()

wait(): Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.

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

notify(): Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened.

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

notifyAll():Wakes up all threads that are waiting on this object's monitor. A thread waits on an object's monitor by calling one of the wait methods.

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

Simple use case for using wait() and notify() : Producer and Consumer problem.

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

Consumer thread has to wait till Producer thread produce data. wait() and notify() are useful in above scenario. Over a period of time, better alternatives have been introduced. Refer to this high level concurrencytutorial page.

消费者线程必须等到生产者线程产生数据。wait() 和 notify() 在上述场景中很有用。在一段时间内,已经引入了更好的替代方案。请参阅此高级并发教程页面。

In simple terms:

简单来说:

Use synchronizedto guard protect critical section of your data and guard your code.

用于synchronized保护数据的关键部分并保护您的代码。

Use wait()and notify()along with synchronization if you want to establish communication between multiple threads in safe manner, which are interdependent on each other.

如果要以安全的方式在相互依赖的多个线程之间建立通信,请使用wait()notify()与同步一起使用。

Related SE questions:

相关 SE 问题:

What does 'synchronized' mean?

“同步”是什么意思?

A simple scenario using wait() and notify() in java

java中使用wait()和notify()的简单场景

回答by Louis Wasserman

Effective Java item 69: "Given the difficulty of using wait and notify correctly, you should use the higher-level concurrency utilities instead."

有效的 Java 条款 69:“鉴于正确使用等待和通知的困难,您应该改用更高级别的并发实用程序。”

Avoid using wait() and notify(): use synchronized, or other utilities from java.util.concurrent, when possible.

尽可能避免使用 wait() 和 notify(): usesynchronizedjava.util.concurrent 中的其他实用程序。

回答by Nidhya

Synchronised block is used, if 2 threads of "same object" tries to accquire the lock. Since object class holds the lock, it knows who to give. Whereas, if 2 threads(say t2 and t4) of 2 objects( t1 & t2 of obj1 and t3 & t4 of obj 2) try to acquire the lock, obj1 would be unaware of obj2's lock and obj2 would be unaware of obj1's lock. Hence wait and notify methods are used.

如果“同一对象”的 2 个线程试图获取锁,则使用同步块。由于对象类持有锁,它知道给谁。然而,如果 2 个对象的 2 个线程(比如 t2 和 t4)(obj1 的 t1 & t2 和 obj 2 的 t3 & t4)尝试获取锁,obj1 将不知道 obj2 的锁,而 obj2 将不知道 obj1 的锁。因此使用了等待和通知方法。

eg:

例如:

//example of java synchronized method  
class Table{  
 synchronized void printTable(int n){//synchronized method  
   for(int i=1;i<=5;i++){  
     System.out.println(n*i);  
     try{  
      Thread.sleep(400);  
     }catch(Exception e){System.out.println(e);}  
   }  

 }  
}  

class MyThread1 extends Thread{  
Table t;  
MyThread1(Table t){  
this.t=t;  
}  
public void run(){  
t.printTable(5);  
}  

}  
class MyThread2 extends Thread{  
Table t;  
MyThread2(Table t){  
this.t=t;  
}  
public void run(){  
t.printTable(100);  
}  
}  

public class TestSynchronization2{  
public static void main(String args[]){  
Table obj = new Table();//only one object  
MyThread1 t1=new MyThread1(obj);  
MyThread2 t2=new MyThread2(obj);  
t1.start();  
t2.start();  
}  
} 

Two threads t1 and t2 belongs to same object, hence synchronization works fine here. Whereas,

两个线程 t1 和 t2 属于同一个对象,因此同步在这里工作正常。然而,

class Table{  
 synchronized void printTable(int n){//synchronized method  
   for(int i=1;i<=5;i++){  
     System.out.println(n*i);  
     try{  
      Thread.sleep(400);  
     }catch(Exception e){System.out.println(e);}  
   }  

 }  
}  

class MyThread1 extends Thread{  
Table t;  
MyThread1(Table t){  
this.t=t;  
}  
public void run(){  
t.printTable(5);  
}  

}  
class MyThread2 extends Thread{  
Table t;  
MyThread2(Table t){  
this.t=t;  
}  
public void run(){  
t.printTable(100);  
}  
}  

public class TestSynchronization2{  
public static void main(String args[]){  
Table obj = new Table();
Table obj1 = new Table();
MyThread1 t1=new MyThread1(obj);  
MyThread2 t2=new MyThread2(obj1);  
t1.start();  
t2.start();  
}  
} 

When you run the above program, synchronisation does not work since each thread belong to different object, Hence you should use wait and notify here.

当您运行上述程序时,由于每个线程属于不同的对象,因此同步不起作用,因此您应该在这里使用等待和通知。

回答by Jiyong Park

wait/notify is required when you want to wait for some condition (e.g. user input) INSIDEa synchronized block.

当你想等待一些条件(例如,用户输入)的等待/通知需要INSIDE同步块。

Typical usage:

典型用法:

synchronized(obj) {
    // do something

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

Let's assume that you don't use wait(). Then, you have to implement busy loop polling the condition that you want, which is bad for performance.

假设您不使用wait()。然后,您必须实现繁忙循环轮询所需的条件,这对性能不利。

synchronized(obj) {
    // do something

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

    // do something other
}

Important note: Even though a thread is awaken by notify() or notifyAll() from other thread, the awaken thread does NOTguaranteed to immediately resume its execution. If there were other threads awaiting to execute a synchronized block on the same object, then the awaken thread should compete with the threads.

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