2015-07-07 2 views
0

Я такой кода:Есть ли лучший способ использовать ожидание/оповещать связи с AtomicInteger

public class RecursiveQueue { 
    //@Inject 
    private QueueService queueService; 
    public static void main(String[] args) { 
     RecursiveQueue test = new RecursiveQueue(); 
     test.enqueue(new Node("X"), true); 
     test.enqueue(new Node("Y"), false); 
     test.enqueue(new Node("Z"), false); 
    } 

    private void enqueue(final Node node, final boolean waitTillFinished) { 
     final AtomicLong totalDuration = new AtomicLong(0L); 
     final AtomicInteger counter = new AtomicInteger(0); 

     AfterCallback callback= new AfterCallback() { 
      @Override 
      public void onFinish(Result result) { 
       for(Node aNode : result.getChildren()) { 
        counter.incrementAndGet(); 
        queueService.requestProcess(aNode, this); 
       } 

       totalDuration.addAndGet(result.getDuration()); 
       if(counter.decrementAndGet() <= 0) { //last one 
        System.out.println("Processing of " + node.toString() + " has finished in " + totalDuration.get() + " ms"); 
        if(waitTillFinished) { 
         counter.notify(); 
        } 
       } 
      } 
     }; 

     counter.incrementAndGet(); 
     queueService.requestProcess(node, callback); 
     if(waitTillFinished) { 
      try { 
       counter.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

Imagine есть queueService, который использует блокировку очереди и несколько потребительских потоков для обработки узлов = вызывает DAO для получения дочерних узлов (это дерево). Таким образом, метод requestProcess просто обводит узел и не блокирует его.

Есть ли лучший/безопасный способ избежать использования wait/notify в этом примере? Согласно некоторым выводам, я могу использовать Phaser (но я работаю над java 6) или условиями (но я не использую блокировки).

ответ

0

Я думаю, что вы ищете CountDownLatch.

+0

Не совсем так, как это требует предварительного знания узлов, подлежащих обработке, и это знание может быть получено только путем обработки родительских узлов. –

3
  • Нет ни одного примера в вашем примере. Вы не должны звонить o.wait() или o.notify(), за исключением из-за блока synchronized(o) {...}.

  • Ваш звонок wait() не находится в цикле. Это может не произойти в вашей JVM, но спецификация языка позволяет wait() вернуться преждевременно (это называется ложным пробуждением). В более общем плане, рекомендуется всегда использовать цикл, потому что это знакомый шаблон дизайна. Заявление A while стоит не более if, а вы должны иметь это из-за возможности побочного пробуждения, и вы абсолютно должны были бы должны иметь его в ситуации с несколькими потребителями, и поэтому вы могли бы просто всегда напишите так.

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

  • Эта «рекурсивная» вещь кажется ужасно сложной, что при обратном вызове добавляет больше предметов в очередь. Как глубоко это может быть?

+0

Спасибо, кажется, что почти ответил на вопрос. Дерево имеет максимальную глубину 5 или что-то в этом роде. Эта очередь обрабатывает «запросы» из разных источников, и нет необходимости немедленно возвращаться (она используется для загрузки данных во временный кеш для будущего использования. Да, я забыл написать 'wait/notify' правильно (я написал это быстро) Итак, есть ли способ сделать это в Java 6 без «синхронизированных» блоков и без низкого уровня 'wait/notify', или я лучше сделаю это? – czs

+0

@czs, Извините, но в вашем вопросе информации недостаточно.Синхронизация - это защита _shared data_ от коррупции, когда одновременно работают два или более потоков. Ваш пример - отдельная демонстрация, которая не создает никаких новых потоков. Вам нужно будет изменить его, чтобы использовать код в любой другой программе. Как будет выглядеть эта другая программа? Какие потоки будут делиться данными? Какие данные они бы разделили? Что такое 'QueueService'? Что делает 'requestProcess (...)' do? Какую проблему ты пытаешься решить? –

0

Вы действительно используете блокировки или, скажем так, вы должны использовать их, если попытаетесь использовать wait/notify, как указал Джеймс. Поскольку вы привязаны к Java 1.6, а ForkJoin или Phaser недоступны для вас, выбор - либо выполнить wait/notify правильно, либо использовать Condition с явным блокировкой. Это будет вопрос ваших личных предпочтений.

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

Смежные вопросы