在多线程中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; } }
想要了解更多开发技术,面试教程以及互联网公司内推,欢迎关注个人微信公众号!将会不按期的发放福利哦~