Философия Java

         

Ожидание и уведомление


Из первых двух примеров очень важно понять, как sleep(), так и suspend() не освобождают блокировку во время своего вызова. Вы должны знать об этом когда работает с блокировками. С другой стороны, методwait( ) освобождает блокировку во время своего вызова, что означает, что другие,  synchronized методы в объекте процесса могут быть вызваны во время wait(). В следующих двух классах видно, что метод run() полностью synchronized в обоих классах, однако Peeker все также имеет полный доступ к synchronized методам во время wait(). Это происходит из-за того, что wait() освобождает блокировку объекта после приостановки метода из которого он вызван.

Также видно, что существуют две формы wait(). Первая принимает аргумент в миллисекундах, что имеет то же значение как и в sleep(): остановку на это время. Различие в том, что в wait() блокировка объекта освобождается и вы можете выйти из wait() с помощью notify() так же как и после истечения времени.

Вторая форма без передачи параметров означает, что wait() будет выполняться до тех пор пока не будет вызвано notify() и не остановится автоматически по истечению времени.

Один, довольно уникальный аспект wait( ) и notify( ) в том, что оба метода являются частью базового класса Object, а не частью Thread, как sleep( ), suspend( ) и resume( ). Хотя это и выглядит немного странно в начале - сделать то, что должно относиться исключительно к процессу доступным для базового класса - это необходимо, так как он управляет блокировками, которые являются частью каждого объекта. В результате можно поместить wait() в любой syncronized метод, в зависимости от того, будет ли какой-либо процесс выполнять именно данный класс. Фактически, единственное применение для wait() быть вызванным из synchronized метода или блокировки. Если вызвать wait() или notify() в необъявленном как synchronuzed методе, то программа будет прекрасно компилироваться, но когда вы ее запустите, то получите IllegalMonitorStateException с каким-то не сразу понятным сообщением "current thread not owner" (текущий процесс не владелец). Запомните, что sleep(), suspend() и resume() могут быть вызваны из не-syncronized методов, поскольку они не управляют блокировкой.


Вы можете вызвать wait() или notify() только для вашей собственной блокировки. Еще раз, вы сможете скомпилировать код, который пытается использовать неверную блокировку, но это приведет вас к тому самому IllegalMonitorStateException сообщению как и прежде. Также ни чего не получиться с чужой блокировкой, но можно попросить другой объект выполнить операцию с его собственной блокировкой. Таким образом одна из попыток заключается в создании syncronized метода, который вызывает notify() для своего собственного объекта. Однако в Notifier видим вызов notify() из syncronized блока:

synchronized(wn2) {   wn2.notify(); }

где wn2 объекта типа WaitNotify2. Этот, не являющийся частью WaitNotifier2, метод, имеет  блокировку на объект wn2 и с этого момента он совершенно спокойно может вызвать notify() для wn2 и не получить IllegalMonitorStateException.

///:Continuing

/////////// Blocking via wait() ///////////

class WaitNotify1 extends Blockable { public WaitNotify1(Container c) { super(c); } public synchronized void run() { while(true) { i++; update(); try { wait(1000); } catch(InterruptedException e) { System.err.println("Interrupted"); } } } }

class WaitNotify2 extends Blockable { public WaitNotify2(Container c) { super(c); new Notifier(this); } public synchronized void run() { while(true) { i++; update(); try { wait(); } catch(InterruptedException e) { System.err.println("Interrupted"); } } } }

class Notifier extends Thread { private WaitNotify2 wn2; public Notifier(WaitNotify2 wn2) { this.wn2 = wn2; start(); } public void run() { while(true) { try { sleep(2000); } catch(InterruptedException e) { System.err.println("Interrupted"); } synchronized(wn2) { wn2.notify(); } } } } ///:Continued

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


Содержание раздела