Подтвердить что ты не робот

Разница между синхронизированным блоком с wait/notify и без них?

Если я просто использую синхронизированный, а не метод wait/notify, сохранит ли он потокобезопасность?

Какая разница?

спасибо заранее.

4b9b3361

Ответ 1

Использование synchronized делает метод/блок доступным только по потоку за раз. Итак, да, это поточно-безопасный.

Оба понятия объединены, а не взаимоисключающие. Когда вы используете wait(), вам нужно владеть монитором на этом объекте. Поэтому перед этим нужно иметь synchronized(..). Использование .wait() делает текущий поток остановленным, пока другой поток не вызовет .notify() на ожидаемом объекте. Это дополнение к synchronized, которое просто гарантирует, что только один поток войдет в блок/метод.

Ответ 2

Поэтому, просто смутившись в ответе на вопрос об этом, я решил поискать его и снова понять в миллиардный раз.

synchronized блок делает поток кода безопасным. Никаких сомнений насчет этого. Когда приходят wait() и notifyAll() notify() или notifyAll() вы пытаетесь написать более эффективный код. Например, если у вас есть список элементов, которые совместно используются несколькими потоками, то, если вы поместите его в synchronized блок монитора, потоки потоков будут постоянно подключаться и выполнять код взад и вперед, взад и вперед во время переключения контекста...... даже с пустым списком!

Следовательно, wait() используется на мониторе (объект внутри синхронизированного (..)) в качестве механизма, позволяющего всем потокам охлаждаться и останавливать использование циклов ЦП до дальнейшего уведомления или notifyAll().

так что-то вроде:

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

...где-нибудь еще...

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

Ответ 3

Метод synchronized имеет два эффекта:

Во-первых, невозможно, чтобы две вызовы синхронизированных методов на одном объекте чередовали. Когда один поток выполняет синхронизированный метод для объекта, все остальные потоки, которые вызывают синхронизированные методы для одного и того же объекта (приостанавливают выполнение) до тех пор, пока первый поток не будет выполнен с объектом

Во-вторых, когда синхронизированный метод завершается, он автоматически устанавливает связь между событиями и последующим вызовом синхронизированного метода для одного и того же объекта. Это гарантирует, что изменения состояния объекта будут видны для всех потоков.

синхронизация поможет вам защитить критический код.

Если вы хотите установить связь между несколькими потоками, вы должны использовать wait() и notify()/notifyAll()

wait(): Заставляет текущий поток ждать, пока другой поток не вызовет метод notify() или метод notifyAll() для этого объекта.

notify(): Пробуждает один поток, ожидающий этого монитора объекта. Если на этом объекте ждут какие-либо потоки, один из них выбран для пробуждения.

notifyAll(): Пробуждает все потоки, которые ждут этого монитора объекта. Нить ждет монитор объекта, вызвав один из методов ожидания.

Простой вариант использования wait() и notify(): проблема производителя и потребителя.

Потребительский поток должен ждать, пока поток производителя выдаст данные. wait() и notify() полезны в приведенном выше сценарии. С течением времени были введены лучшие альтернативы. Обратитесь к этой странице странице высокого уровня concurrency.

Простыми словами:

Используйте synchronized, чтобы защитить критический раздел ваших данных и защитить свой код.

Используйте wait() и notify() вместе с синхронизацией, если вы хотите безопасно установить связь между несколькими потоками, которые взаимозависимы друг с другом.

Связанные вопросы SE:

Что означает "синхронизированный" ?

Простой сценарий с использованием wait() и notify() в java

Ответ 4

Эффективный Java-пункт 69: "Учитывая сложность использования wait и правильно сообщите, вы должны использовать утилиты более высокого уровня concurrency. "

Избегайте использования wait() и notify(): используйте synchronized или другие утилиты java.util.concurrent, когда это возможно.

Ответ 5

Используется синхронный блок, если 2 потока "того же объекта" пытается установить блокировку. Так как класс объекта содержит блокировку, он знает, кто ему дать. Если 2 потока (например, t2 и t4) из 2 объектов (t1 и t2 obj1 и t3 и t4 obj 2) попытаются получить блокировку, obj1 не будет знать об блокировке obj2, а obj2 не будет знать об блокировке obj1. Поэтому используются методы ожидания и уведомления.

например:

//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();  
}  
} 

Два потока 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();  
}  
} 

Когда вы запускаете вышеуказанную программу, синхронизация не работает, поскольку каждый поток принадлежит к другому объекту. Следовательно, вы должны использовать wait и уведомлять здесь.

Ответ 6

wait/notify требуется, когда вы хотите подождать некоторое условие (например, пользовательский ввод) INSIDE для синхронизированного блока.

Типичное использование:

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
}

Важное примечание. Несмотря на то, что поток пробуждается уведомлением() или notifyAll() из другого потока, пробужденный поток НЕ гарантирует немедленное возобновление его выполнения. Если бы существовали другие потоки, ожидающие выполнения синхронизированного блока на одном и том же объекте, тогда пробуждающийся поток должен конкурировать с потоками.