2014-11-15 4 views
0

У меня есть многопоточная программа, в которой один поток читает данные, а несколько других выполняют работу над этими данными. Если у меня есть один записывающий поток, непрерывно добавляющий данные (Example.add()), а другие потоки считывателей последовательно считывают эти данные (Example.getData(1), Example.getData(2), ...), что является лучшим способом блокировать читателей до тех пор, пока не будут доступны данные по индексу, который они запрашивают ?Заблокировать до тех пор, пока элемент не будет доступен

Эта проблема похожа на производителя-потребителя, но я не хочу «потреблять» данные.

public class Example { 
    private ArrayList<Integer> data; 

    public Example() { 
    data = new ArrayList<Integer>(); 
    } 

    public int getData(int i) { 
    // I want to block here until the element 
    // index i is available. 

    return data.get(i); 
    } 

    public void add(int n) { 
    data.add(n); 
    } 
} 
+0

Это звучит, как вы хотите, либо 'Future' (встроенный в Java, но более ограниченный) или' Promise' (новее, и часть спецификации реактора). – chrylis

ответ

1

Это кажется разумным способом для синхронизации потоков:

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html

ссылка Состояние показывает пример этого:

class BoundedBuffer { 
    final Lock lock = new ReentrantLock(); 
    final Condition notFull = lock.newCondition(); 
    final Condition notEmpty = lock.newCondition(); 

    final Object[] items = new Object[100]; 
    int putptr, takeptr, count; 

    public void put(Object x) throws InterruptedException { 
     lock.lock(); 
     try { 
      while (count == items.length) 
       notFull.await(); 
      items[putptr] = x; 
      if (++putptr == items.length) putptr = 0; 
      ++count; 
      notEmpty.signal(); 
     } finally { 
      lock.unlock(); 
     } 
    } 

    public Object take() throws InterruptedException { 
     lock.lock(); 
     try { 
      while (count == 0) 
       notEmpty.await(); 
      Object x = items[takeptr]; 
      if (++takeptr == items.length) takeptr = 0; 
       --count; 
      notFull.signal(); 
      return x; 
     } finally { 
      lock.unlock(); 
     } 
    } 
} 

Пожалуйста, не судите меня по стилю кода, это прямая копия примера из условия.

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

Если вы хотите, чтобы они специально подождали 1 элемент, вы могли бы сохранить сигнал на элемент, но это кажется излишним.

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

public class Example { 
    private Lock lock = new ReentrantLock(); 
    private Condition update = lock.newCondition(); 
    public Example(data) { 
     data = new ArrayList<Integer>(); 
    } 

    public int getData(int i) { 
     lock.lock(); 
     try { 
      while (data.get(i) == null) { 
       update.await(); 
      } 
      return data.get(i); 
     } finally { 
      lock.unlock(); 
     } 
    } 

    public void add(int n) { 
     data.add(n); 
     update.signal(); 
    } 
} 
+0

Можете ли вы подробнее рассказать о _Basically_? –

+0

Несомненно .. считал, что пример в ссылке условия охватывал большую часть его прецедента. и был ленив: D также над кодом, я кодирую несколько пьяный, так что кто знает, работает ли он. Я думаю, что это так, но нужно тестирование. «Пример (данные)» Я ушел, поскольку ОП использовал эту точную форму. это может быть неправильно, но не хочет исправлять его пример – Joeblade

+0

Мне очень нравится этот метод, @Joeblade. Я попробовал это и сделал некоторые обновления к вашему примеру кода, если кто-нибудь когда-нибудь понадобится сделать что-то подобное. –

1

Вы можете использовать блокирующую очередь в java. Когда очередь пуста, она блокирует для очереди данные, пока она не будет потреблена. Вы можете найти более подробную информацию об этом здесь: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

просмотра Количество некоторые примеры онлайн для Java блокирующей очереди, и вы можете решить ваш вопрос

+0

Очередь не поддерживает их требование индексирования. –

+0

может быть настраиваемая структура данных, которая использует внутреннюю блокировку для реализации этой функции. –

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