貓頭鷹的深夜翻譯:Spring線程 TaskExecutor

前言

在多線程中web應用很常見,尤爲當你須要開發長期任務。html

在Spring中,咱們能夠額外注意並使用框架已經提供的工具,而不是創造咱們本身的線程。java

Spring提供了TaskExecutor做爲Executors的抽象。這個接口相似於java.util.concurrent.Executor接口。在spring中有許多預先開發好的該接口的實現,能夠在官方文檔中詳細查看。web

經過在Spring上下文中配置一個TaskExecutor的實現,你能夠將你的TaskExecutor的實現注入到bean中,並能夠在bean中訪問到該線程池。面試

在bean中使用線程池的方式以下:spring

package com.gkatzioura.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
 * Created by gkatzioura on 4/26/17.
 */
@Service
public class AsynchronousService {
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private TaskExecutor taskExecutor;
    public void executeAsynchronously() {
        taskExecutor.execute(new Runnable() {
            @Override
            public void run() {
                //TODO add long running task
            }
        });
    }
}

配置

首先須要在Spring上下文中註冊一個線程池。微信

package com.gkatzioura.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
/**
 * Created by gkatzioura on 4/26/17.
 */
@Configuration
public class ThreadConfig {
    @Bean
    public TaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(4);
        executor.setMaxPoolSize(4);
        executor.setThreadNamePrefix("default_task_executor_thread");
        executor.initialize();
        return executor;
    }
}

這裏配置了線程池的核心線程數,最大線程數和線程池中線程名稱的前綴。多線程

線程池配置完畢後,接下來的步驟就很簡單了,將線程池注入到spring的component中,而後將Runnable任務提交給線程池來完成。app

因爲咱們的異步代碼可能須要與應用程序的其餘組件交互並注入它們,所以一種不錯的方法是建立Prototype範圍的Runnable實例。(Prototype在每一次調用時會新建一個實例)框架

package com.gkatzioura;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
 * Created by gkatzioura on 10/18/17.
 */
@Component
@Scope("prototype")
public class MyThread implements Runnable {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyThread.class);
    @Override
    public void run() {
        LOGGER.info("Called from thread");
    }
}

而後,咱們將executors注入咱們的服務並使用它來執行可運行的實例。異步

package com.gkatzioura.service;
import com.gkatzioura.MyThread;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
 * Created by gkatzioura on 4/26/17.
 */
@Service
public class AsynchronousService {
    @Autowired
    private TaskExecutor taskExecutor;
    @Autowired
    private ApplicationContext applicationContext;
    public void executeAsynchronously() {
        MyThread myThread = applicationContext.getBean(MyThread.class);
        taskExecutor.execute(myThread);
    }
}

Async關鍵字

經過spring提供的Async關鍵字,咱們甚至無需將異步任務封裝到Runnable類中,直接使用註解便可。

@Async
@Transactional
public void printEmployees() {
 
    List<Employee> employees = entityManager.createQuery("SELECT e FROM Employee e").getResultList();
    employees.stream().forEach(e->System.out.println(e.getEmail()));
}

該類會經過代理的方式提交給默認的線程池。

@Async
@Transactional
public CompletableFuture<List<Employee>> fetchEmployess() {
    List<Employee> employees = entityManager.createQuery("SELECT e FROM Employee e").getResultList();
    return CompletableFuture.completedFuture(employees);
}

該方法會返回異步執行的Future結果。

須要注意,若是要開啓Async關鍵字,則須要在配置中添加EnableAsync信息。

package com.gkatzioura.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 
import java.util.concurrent.Executor;
 
/**
 * Created by gkatzioura on 4/26/17.
 */
@Configuration
@EnableAsync
public class ThreadConfig {
 
    @Bean
    public TaskExecutor threadPoolTaskExecutor() {
 
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(4);
        executor.setMaxPoolSize(4);
        executor.setThreadNamePrefix("sgfgd");
        executor.initialize();
 
        return executor;
    }
 
}

參考文章

spring and async

clipboard.png
想要了解更多開發技術,面試教程以及互聯網公司內推,歡迎關注個人微信公衆號!將會不按期的發放福利哦~

相關文章
相關標籤/搜索