在多線程中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); } }
經過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; } }
想要了解更多開發技術,面試教程以及互聯網公司內推,歡迎關注個人微信公衆號!將會不按期的發放福利哦~