Какой шаблон проектирования использовать для многопоточной очереди - PullRequest
3 голосов
/ 30 апреля 2010

У меня очень сложная система (100+ потоков), которая должна отправлять электронную почту без блокировки. Мое решение проблемы состояло в том, чтобы реализовать класс с именем EmailQueueSender, который запускается в начале выполнения и имеет ScheduledExecutorService, который просматривает внутреннюю очередь каждые 500 мс, а если size ()> 0, то он очищает его.

Пока это происходит, есть синхронизированный статический метод с именем addEmailToQueue(String[]), который принимает электронную почту, содержащую тело, subject..etc в качестве массива. Система работает, и мои другие потоки могут двигаться дальше после добавления своей электронной почты в очередь, не блокируя и даже не беспокоясь, если электронная почта была успешно отправлена ​​... она просто кажется немного грязной ... или хакерской ... Каждый программист это чувство возникает у них в животе, когда они знают, что делают что-то не так или есть лучший способ. Тем не менее, кто-то может дать мне пощечину и предложить более эффективный способ сделать это?

Спасибо!

Ответы [ 5 ]

5 голосов
/ 30 апреля 2010

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/ThreadPoolExecutor.html

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

3 голосов
/ 30 апреля 2010

Если вы используете Java 6, то вы можете интенсивно использовать примитивы в пакете java.util.concurrent.

Наличие отдельного потока, который обрабатывает реальную отправку, совершенно нормально. Вместо того, чтобы опрашивать очередь, я бы предпочел использовать BlockingQueue, поскольку вы можете использовать блокировку take() вместо ожидания занятости.

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

Вместо массива Strings я бы рекомендовал создать (почти тривиальный) класс Java для хранения значений. Создание объектов в наши дни дешевое.

1 голос
/ 30 апреля 2010

Я не уверен, что это будет работать для вашего приложения, но звучит так, как будто это будет. ThreadPoolExecutor (реализация ExecutorService) может принимать BlockingQueue в качестве аргумента, и вы можете просто добавить новые потоки в очередь. Когда вы закончите, вы просто прекратите действие ThreadPoolExecutor.

private BlockingQueue<Runnable> queue; 
... 
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, new Long(1000),  
                TimeUnit.MILLISECONDS, this.queue);

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

 if (issuedThreads == pool.getCompletedTaskCount()) { 
        pool.shutdown(); 
    } 

Если две пары совпадают, все готово. Другой способ завершить пул - это подождать секунду в цикле:

try { 
      while (!this.pool.awaitTermination(1000, TimeUnit.MILLISECONDS)); 
} catch (InterruptedException e) {//log exception...} 
0 голосов
/ 30 апреля 2010

Существует множество пакетов и инструментов, которые могут помочь с этим, но общее название для подобных случаев, широко изученное в информатике, - проблема производитель-потребитель . Для этого существуют различные известные решения, которые можно считать «шаблонами проектирования».

0 голосов
/ 30 апреля 2010

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

Под платформой Spring использует Java Mail для почтовой части и позволяет выбирать между ThreadPoolExecutor (как упомянуто @Lorenzo) или Quartz. Кварц, на мой взгляд, лучше, потому что вы можете даже настроить его так, чтобы он запускал ваши задания в фиксированные моменты времени, например, задания cron (например, в полночь). Преимущество использования Spring состоит в том, что он значительно упрощает работу с этими пакетами, поэтому ваша работа становится еще проще.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...