Конвертировать код wait & notifyAll для использования объекта Java 1.5 Lock - PullRequest
5 голосов
/ 04 мая 2011

Мы используем код, который использует синхронизированные блоки вокруг сегментов кода с большим количеством вызовов wait и notifyAll (). Мы пытаемся преобразовать их для использования методов Java 5 Lock.lock () и Lock.unlock (). Как перенести этот код, чтобы удалить все вызовы wait и notifyAll. Я не знаю эквивалента этому при использовании новых функций блокировки.

Любые ссылки с примерами приветствуются.

Заранее спасибо

Уравнение, следующий код должен быть преобразован для использования Lock.lock () и lock.unlock. Первая часть для удаления синхронизированного блока проста, так как мне просто нужно вызвать метод lock (). Вопрос в том, что можно сделать для методов notifyAll () и wait.

     synchronized( LOCK )
            {
                while( !Thread.interrupted() )
                {
                 try
                    {

                        working = runRules();

                        if( !working )
                            LOCK.notifyAll();

                        LOCK.wait( working ? shortTimeout : longTimeout );
                    }
                    catch( final InterruptedException e )
                    {
                        Package.log.info( "Thread was interrupted.  Exiting.", e );
                        return;
                    }
                }
            }

Ответы [ 3 ]

7 голосов
/ 04 мая 2011

Используйте Condition s, предоставляемые пакетом java.util.concurrent.locks :

 final Object monitor = ...

 ...

 synchronized (monitor) {

     while (!condition) monitor.wait();
     ... do something ...
 }

становится:

 final ReentrantLock lock = ...;
 final Condition cvar = lock.newCondition();

 ...

 lock.lock();

 try {

     while (!condition) cvar.await();
     ... do something ... 

 } finally {

     lock.unlock();
 }

Сторона сигнализации очень похожа:

 synchronized (monitor) {

      ... do something ...
      monitor.notify();
 }

становится:

 lock.lock();

 try {

     ... do something ...
     cvar.signalAll();

 } finally {

     lock.unlock();
 }
4 голосов
/ 04 мая 2011

Используйте Condition объекты, предоставленные фабричным методом Lock.newCondition().В этот интерфейс были включены аспекты ожидания и уведомления монитора объекта.

С точки зрения миграции:

  • wait() -> await()
  • wait(long) -> await(long, TimeUnit.Millis) или awaitNanos(long * 10000000)
  • notify() -> signal()
  • notifyAll() -> signalAll()

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

Существуют также дополнительные await вариантыкоторые позволяют вам ждать без прерывания и ждать до определенной конкретной даты (времени).

Javadocs класса Condition очень хороши и описывают его и его использование в большомподробно.

0 голосов
/ 09 июня 2017

Поскольку этот вопрос касается notifyAll, я попробовал несколько примеров производителя / потребителя с phaser.Я не использовал Lock, так как для этого нужно попытаться / наконец, условие объекта, и до разблокировки другой поток не будет работать ... и т. Д.

import java.util.concurrent.Phaser;

public class ProducerConsumerExample {

    Phaser producer;
    Phaser consumers;
    volatile String array[];

    public void init() {
        producer = new Phaser(5);
        consumers = new Phaser(5);
        Consumer l1 = new Consumer("Consumer_1");
        l1.setDaemon(true);
        l1.start();
        Consumer l2 = new Consumer("Consumer_2");
        l2.setDaemon(true);
        l2.start();
        Consumer l3 = new Consumer("Consumer_3");
        l3.setDaemon(true);
        l3.start();
        Consumer l4 = new Consumer("Consumer_4");
        l4.setDaemon(true);
        l4.start();
    }

    class Consumer extends Thread {

        Consumer(String name) {
            super(name);
        }

        private void printMethod(String i) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }

        public void run() {
            while (true) {
                //make the consumers sleep till producer produces
                consumers.arriveAndAwaitAdvance();
                for (int i = 0; i < array.length; i++) {
                    printMethod(array[i]);
                }
                //alert the producer to start 
                producer.arriveAndAwaitAdvance();
                System.out.println(Thread.currentThread().getName() + " thread wakeup but will stuck with consumers.arriveAndAwaitAdvance!");

            }
        }
    }

    public void run() {
        for (int j = 0; j < 3; j++) {
            array = new String[5];
            for (int i = 0; i < array.length; i++) {
                array[i] = "Phase_" + (j + 1) + " Count_" + (i + 1);
            }
            System.out.println("Main thread pushed data.");
            //alert the consumers to start 
            consumers.arriveAndAwaitAdvance();

            //make the producer sleep till all the consumer consumes
            producer.arriveAndAwaitAdvance();   
            System.out.println("Main thread wakeup and will start pushing data...");

        }
    }

    public static void main(String[] args) {
        ProducerConsumerExample sch = new ProducerConsumerExample();
        sch.init();
        sch.run();
        System.out.println("Main thread completed, producing data.");
    }
}
...