Что делает synchronized () / wait () / notifyAll () в Java?

Возможный дубликат:
Синхронизация Java

Я читаю книгу « Начало игр для Android» .

Он использует synchronized() много, но я действительно не понимаю, что он делает. Я не использовал Java в течение длительного времени, и я не уверен, что когда-либо использовал многопоточность.

В примерах Canvas используется synchronized(this) . Однако в примере OpenGL ES он создает объект с именем stateChanged а затем использует synchronized(stateChanged) . Когда изменяется состояние игры, он вызывает stateChanged.wait() а затем stateChanged.notifyAll();

Некоторый код:

  Object stateChanged = new Object(); //The onPause() looks like this: public void onPause() { synchronized(stateChanged) { if(isFinishing()) state = GLGameState.Finished; else state = GLGameState.Paused; while(true) { try { stateChanged.wait(); break; } catch(InterruptedException e) { } } } } //The onDrawSurface looks like this: public void onDrawFrame(GL10 gl) { GLGameState state = null; synchronized(stateChanged) { state = this.state; } if(state == GLGameState.Running) { } if(state == GLGameState.Paused) { synchronized(stateChanged) { this.state = GLGameState.Idle; stateChanged.notifyAll(); } } if(state == GLGameState.Finished) { synchronized(stateChanged) { this.state = GLGameState.Idle; stateChanged.notifyAll(); } } } //the onResume() looks like this: synchronized(stateChanged) { state = GLGameState.Running; startTime = System.nanoTime(); } в  Object stateChanged = new Object(); //The onPause() looks like this: public void onPause() { synchronized(stateChanged) { if(isFinishing()) state = GLGameState.Finished; else state = GLGameState.Paused; while(true) { try { stateChanged.wait(); break; } catch(InterruptedException e) { } } } } //The onDrawSurface looks like this: public void onDrawFrame(GL10 gl) { GLGameState state = null; synchronized(stateChanged) { state = this.state; } if(state == GLGameState.Running) { } if(state == GLGameState.Paused) { synchronized(stateChanged) { this.state = GLGameState.Idle; stateChanged.notifyAll(); } } if(state == GLGameState.Finished) { synchronized(stateChanged) { this.state = GLGameState.Idle; stateChanged.notifyAll(); } } } //the onResume() looks like this: synchronized(stateChanged) { state = GLGameState.Running; startTime = System.nanoTime(); } 

Solutions Collecting From Web of "Что делает synchronized () / wait () / notifyAll () в Java?"

Этот учебник по Java, вероятно, поможет вам понять, что использует синхронизация на объекте.

Когда object.wait() он освободит блокировку, удерживаемую на этом объекте (что происходит, когда вы говорите, что synchronized(object) ), и заморозите поток. Затем поток ожидает, пока object.notify() или object.notifyAll() вызывается отдельным потоком. Как только один из этих вызовов произойдет, он позволит остановить любые потоки из-за object.wait() для продолжения. Это не означает, что поток, который вызвал object.notify() или object.notifyAll() будет заморозить и передать управление ожидающему потоку, это просто означает, что эти ожидающие потоки теперь могут продолжать, тогда как раньше они не были.

synchronized ключевое слово используется, чтобы поддерживать переменные или методы поточно-безопасными. Если вы переносите переменную в синхронизированный блок следующим образом:

 synchronized(myVar) { // Logic involing myVar } 

Тогда любые попытки изменить значение myVar из другого потока, пока выполняется логика внутри синхронизированного блока, будут ждать завершения выполнения блока. Он гарантирует, что значение, идущее в блок, будет одинаковым по жизненному циклу этого блока.

При использовании следующим образом:

 private synchronized void someMehtod() 

Вы получаете эти эффекты:

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

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

(Взято отсюда )

Вы получаете аналогичный эффект при использовании синхронизированного блока кода:

 private void someMethod() { // some actions... synchronized(this) { // code here has synchronized access } // more actions... } 

Как поясняется здесь

Java (на базе которого Android) может работать под несколькими потоками, которые могут использовать несколько ядер процессора. Многопоточность означает, что вы можете заставить Java выполнять два процесса в один и тот же момент. Если у вас есть блок кода или метод, который вам нужно обеспечить, можно управлять только одним потоком за раз, вы синхронизируете этот блок кода.

Вот официальное объяснение Java от Oracle

Важно знать, что затраты на процессор / io связаны с использованием синхронизации, и вы хотите использовать его только тогда, когда вам это нужно. Также важно исследовать, какие классы / методы Java являются потокобезопасными. Например, оператор приращения ++ не является защищенным потоком, тогда как вы можете легко создать блок синхронизированного кода, который увеличивает значение с помощью + = 1.

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

Синхронизированное ключевое слово в java используется для двух вещей.

Первое значение – это так называемый критический раздел, то есть часть кода, к которой можно одновременно обращаться одним потоком. Объект, который вы передаете для synchronized допускает какое-то именование: если один код запускается synchronized(a) он не может получить доступ к другому блоку, который synchronized(a) но может получить доступ к блоку кода в synchronized(b) .

Другой проблемой является межпоточная связь. Тема может ждать, пока другой поток не сообщит об этом. Оба ожидания и уведомления должны быть записаны в synchronized блок.

Это было очень короткое описание. Я бы предложил вам найти учебник по многопоточности и прочитать его.

Синхронизированное ключевое слово вместе с операциями wait и notify формирует монитор неблокирующего состояния , конструкцию, полезную для координации нескольких потоков.