Java ExecutorService顺序-Spring MVC

Java ExecutorService sequentially -Spring MVC

我想在我的 Spring-MVC 应用程序中实现 ExecutorService。

我需要一个全局的 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,然后将 Task(Runnable 对象)传递给方法:

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

但是,我有几个问题:

我不确定如何将它集成到我有控制器、服务等的 Spring MVC 应用程序中。

应用程序从网络服务接收一些通知。这些通知将在代码中的不同位置进行处理。我想要 依次执行它们。所以我需要异步识别我想要 运行 的所有任务,然后将它们传递给包装在 Runnabel 对象中的上述方法 (`addTaskToQueue),这样它们就可以异步执行。这是正确的方法吗?

所以我总是传递一个Runnable对象给这个方法来执行它。此方法执行它并关闭 executorservice。因此,每次我将任务传递给该服务时,它都会创建一个新服务,然后将其关闭。但我不想那样做——我希望 executorservice 保持活动状态并执行即将到来的任务,而不是在每个任务后关闭。我该如何实现?

或者我以这种方式实现它是完全错误的吗?

编辑:

使用 Spring 提供的 TaskExecutor - 我会这样实现它:

@Autowired
private TaskExecutor taskExecutor;

然后在我的代码中从不同的位置调用它:

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

可能我需要确保配置中的某处需要按顺序执行 - 所以它应该只创建 1 个线程。从不同的地方调用它安全吗?它不会总是使用新队列创建新服务吗?

Spring 已经有一个用于此的 bean:org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor。它实现 DisposableBean 接口,当 Spring 上下文被销毁时调用 shutdown() 方法。

  <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>

Singleton 设计模式不太适合这种情况。由于您使用的是 Spring,因此使用 @PostConstruct@PreDestroy 方法制作组件更有意义。 Here and here 是对此进行解释的文章。

对于您的情况,我会执行以下操作:

@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);
    }
}

然后你就可以自动装配这个组件了。

编辑:@Ivan 的回答是首选。