Java ExecutorService последовательно -Spring MVC - PullRequest
0 голосов
/ 01 мая 2018

Я хочу реализовать ExecutorService в моем приложении Spring-MVC.

Мне нужен глобальный ExecutorService, который принимает задачи, помещает их в очередь, а затем выполняет их последовательно. Поэтому я хочу передать задачи из разных мест в приложении. Поэтому я использую Executors.newSingleThreadExecutor();, поэтому у меня есть только 1 поток, выполняющий эти задачи.

Однако я не уверен, как интегрировать его в приложение Spring:

public enum TaskQueue {

    INSTANCE;

    ExecutorService executorService;

    private TaskQueue() {
        executorService = Executors.newSingleThreadExecutor();
    }

    public void addTaskToQueue (Runnable task){
        executorService.submit(task);
        executorService.shutdown();
    }
}

Итак, я думаю о создании Singleton, а затем просто передать задачу (Runnable объект) методу:

TaskQueue.INSTANCE.addTaskToQueue(new Runnable() {
 @Override
  public void run() {
      System.out.println("Executing Task1 inside : " + Thread.currentThread().getName());
        }
    });

Однако у меня есть несколько вопросов:

Я не уверен, как интегрировать его в приложение Spring MVC, где у меня есть контроллеры, службы и т. Д.

Приложение получает уведомления от веб-службы. Эти уведомления будут обрабатываться в разных местах кода. я бы хотел выполнять их последовательно. Поэтому мне нужно определить все задачи, которые я хочу выполнить асинхронно, а затем передать их описанному выше методу (`addTaskToQueue), обернутому в объект Runnabel, чтобы они могли выполняться асинхронно. Это правильный подход?

Поэтому я всегда передаю объекты Runnable этому методу для его выполнения. Этот метод выполняет его и закрывает службу executor. Поэтому каждый раз, когда я передаю задание этому сервису, он создает новый сервис, а затем закрывает его. Но я не хочу иметь это - я хочу, чтобы executorservice оставался в живых и выполнял задачи, которые приходят, а не закрываются после каждой задачи. Как мне этого добиться?

Или я совершенно не прав, реализовав это таким образом?

EDIT:

Используя TaskExecutor, предоставленный Spring - я бы реализовал его так:

@Autowired
private TaskExecutor taskExecutor;

Тогда звоню из другого места в моем коде:

taskExecutor.execute(new Runnable() {
        @Override
        public void run() {
            //TODO add long running task
        }
    });

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

Ответы [ 2 ]

0 голосов
/ 01 мая 2018

Шаблон проектирования Singleton не очень подходит для этого. Поскольку вы используете Spring, имеет смысл создавать компоненты с методами @PostConstruct и @PreDestroy. Здесь и здесь - статьи, объясняющие это.

В вашем случае я бы сделал что-то вроде следующего:

@Component
public class TaskQueue {

    private ExecutorService executorService;

    @PostConstruct
    public void init() {
        executorService = Executors.newSingleThreadExecutor();
    }

    @PreDestroy
    public void cleanup() {
        executorService.shutdown();
    }

    public void addTaskToQueue (Runnable task){
        executorService.submit(task);
    }
}

И затем вы можете автоматически подключить этот компонент.

Редактировать: @ Иван должен быть предпочтительным.

0 голосов
/ 01 мая 2018

У Spring уже есть компонент для этого: org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor. Он реализует интерфейс DisposableBean и метод shutdown() вызывается при разрушении контекста Spring.

  <bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="${threadPoolSize}"/>
    <property name="maxPoolSize" value="${threadPoolSize}"/>
    <property name="WaitForTasksToCompleteOnShutdown" value="false"/>
  </bean>
...