如何友好地关闭Spring引导线程池项目,这是24x7运行

时间:2017-12-26 22:32:55

标签: spring multithreading spring-boot pool

我创建了一个spring boot thread pool项目,该项目有一个需要在生成时运行24x7的线程,但是当我需要在服务器中停止应用程序进行某些维护时,它应该在完成当前任务后关闭,而不是接受任何新任务。

我的代码是: 配置类

@Configuration
public class ThreadConfig {
    @Bean
    public ThreadPoolTaskExecutor taskExecutor(){
    ThreadPoolTaskExecutor executorPool = new ThreadPoolTaskExecutor();
    executorPool.setCorePoolSize(10);
    executorPool.setMaxPoolSize(20);
    executorPool.setQueueCapacity(10);
    executorPool.setWaitForTasksToCompleteOnShutdown(true);
    executorPool.setAwaitTerminationSeconds(60);
    executorPool.initialize();

    return executorPool;
}
}

Runnable class

@Component
@Scope("prototype")
public class DataMigration implements Runnable {

String name;

private boolean run=true;

public DataMigration(String name) {
    this.name = name;
}

@Override
public void run() {
    while(run){

    System.out.println(Thread.currentThread().getName()+" Start Thread = "+name);
    processCommand();
    System.out.println(Thread.currentThread().getName()+" End Thread = "+name);
    if(Thread.currentThread().isInterrupted()){
        System.out.println("Thread Is Interrupted");
        break;
    }

    }
}

private void processCommand() {
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

public void shutdown(){
    this.run = false;
}

}

主要课程:

@SpringBootApplication
public class DataMigrationPocApplication implements CommandLineRunner{

@Autowired
private ThreadPoolTaskExecutor taskExecutor;

public static void main(String[] args) {
    SpringApplication.run(DataMigrationPocApplication.class, args);
}

@Override
public void run(String... arg0) throws Exception {

    for(int i = 1; i<=20 ; i++){
        taskExecutor.execute(new DataMigration("Task " + i));
    }

    for (;;) {
        int count = taskExecutor.getActiveCount();
        System.out.println("Active Threads : " + count);
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (count == 0) {
            taskExecutor.shutdown();
            break;
        }

    }
    System.out.println("Finished all threads");

}
}

我需要帮助才能理解我是否需要停止弹簧启动应用程序它应该停止运行的所有20个线程(24x7),否则在完成while循环和退出时的当前循环之后。

1 个答案:

答案 0 :(得分:0)

我会在此代码中提出一些更改来解决问题

1)因为在你的POC processCommand中调用Thread.sleep,当你关闭执行程序并且它中断了工作程序InterruptedException被调用但在代码中几乎被忽略。之后有 if(Thread.currentThread()。isInterrupted())检查哪个将返回false,原因如上。类似的问题在下面的帖子中列出

how does thread.interrupt() sets the flag?

以下代码更改应解决问题:

private void processCommand() {
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
        shutdown();
    }
}

2)还因为ThreadConfig :: taskExecutor executorPool.setWaitForTasksToCompleteOnShutdown(true)Spring将调用executor.shutdown而不是executor.shutdownNow。根据{{​​3}} ExecutorService.shutdown

  

启动以前提交的任务的有序关闭   已执行,但不会接受任何新任务。

所以我建议设置

executorPool.setWaitForTasksToCompleteOnShutdown(false);

此代码中需要改进的其他事项:虽然DataMigration被注释为组件,但此类的实例不是由Spring创建的。您应该尝试使用类似于ThreadConfig :: taskExecutor的工厂方法,以使Spring启动DataMigration实例,例如将其他bean注入DataMigration实例。

为了在linux环境下运行jar文件时关闭执行程序,您可以添加执行器模块并启用关闭端点:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

在application.properties中:

endpoints.shutdown.enabled=true

它将启用JMX关闭端点,您可以在其上调用shutdown。 如果您希望完成任务的当前作业周期,则应设置

executorPool.setWaitForTasksToCompleteOnShutdown(true);

为了远程连接到linux env 上的jvm进程,您必须指定RMI注册表端口。 这是一篇详细的文章: javadoc

如果您只需要从本地环境连接到JMX,您可以运行jsoncole或命令行工具:How to access Spring-boot JMX remotely

以下是使用这些工具之一的示例 - jmxterm

$>run -d org.springframework.boot: -b        org.springframework.boot:name=shutdownEndpoint,type=Endpoint shutdown
#calling operation shutdown of mbean  org.springframework.boot:name=shutdownEndpoint,type=Endpoint with params  []
#operation returns:
{
  message = Shutting down, bye...;
}