2009-03-21 4 views
0

У меня есть приложение-производитель, которое генерирует индекс (сохраняет его в некоторой структуре данных дерева данных в памяти). И потребительское приложение будет использовать индекс для поиска частичных совпадений.дизайн приложения-производителя/потребителя

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

Грубо говоря, я знаю, что для этого вам понадобится протокол wait/notify. Мой вопрос: возможно ли прервать поток производителя, используя wait/notify, когда он делает свой бизнес? Для чего нужны java.util.concurrent примитивы?

ответ

0

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

Вы могли бы потенциально сделать что-то подобное

class Indexer { 

    Lock lock = new ReentrantLock();  

    public void index(){ 
     while(somecondition){ 
      this.lock.lock(); 
      try{ 
       // perform one indexing step 
      }finally{ 
       lock.unlock(); 
      } 
     } 
    } 

    public Item lookup(){ 
     this.lock.lock(); 
     try{ 
      // perform your lookup 
     }finally{ 
      lock.unlock(); 
     } 
    } 
} 

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

Если вы считаете, что у вас может быть больше одного потока, пытающегося выполнить поиск в одно и то же время, возможно, вам стоит взглянуть на интерфейс ReadWriteLock и реализацию ReentrantReadWriteLock.

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

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

Не беспокойтесь о производительности блокировки, в незащищенной блокировке java (когда только один поток пытается захватить замок) дешево. До тех пор, пока большая часть вашей блокировки не имеет значения, производительность блокировки не вызывает беспокойства.

2

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

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

+0

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

0

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

0

Нет, это невозможно.

Единственный способ уведомления потока без явного кода в самом потоке - использовать Thread.interrupt(), что вызовет исключение в потоке. interrrupt() обычно не очень надежна, потому что бросать исключение в какую-то случайную точку в коде - это кошмар, чтобы получить право во всех кодах. Кроме того, одной пробы {} catch (Throwable) {} где-то в потоке (включая любые библиотеки, которые вы используете) может быть достаточно, чтобы проглотить сигнал.

В большинстве случаев единственным правильным решением является использование общего флага или очереди, которую потребитель может использовать для передачи сообщений производителю. Если вы беспокоитесь о том, что производитель не отвечает или замораживает, запустите его в отдельном потоке и потребуйте, чтобы он отправлял сообщения о сердцебите каждые n секунд. Если он не посылает сердцебиение, убейте его. (Обратите внимание, что определение того, действительно ли производитель замораживает, а не просто ждет внешнего события, часто очень сложно получить право).

+0

Здесь есть несколько хороших идей, но есть и некоторые прямые ошибки. Прерывание потока будет * не * поднимать исключение "в некоторой случайной точке". InterruptedExceptions проверены, а методы, которые могут их выбрасывать, четко определены. Плохо написанных блоков «catch-all» достаточно, чтобы разбить любую программу. – erickson

+0

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

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