2010-04-30 7 views
3

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

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

Спасибо!

ответ

3

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

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

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

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

+0

Только то, что мне нужно! Уже реализованы и работают отлично. Я также изменил электронную почту на внутренний класс, а не на массив .... Большое вам спасибо :) – Submerged

+0

j.u.c вышел в java 5 –

5

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

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

0

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

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

0

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

1

Я не уверен, что это сработает для вашего приложения, но звучит так. A ThreadPoolExecutor (ExecutorService -implementation) может принимать в качестве аргумента 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...} 
Смежные вопросы