原文链接
代码地址:https://github.com/Snowstorm0...
1 线程同步和异步
线程同步:A线程要申请某个资源,然而此资源正在被B线程应用中,因为同步机制存在,A只能期待上来。耗时较长,安全性较高。
线程异步:A线程要申请某个资源,然而此资源正在被B线程应用中,因为没有同步机制存在,A线程依然申请的到。
一个过程启动的多个不相干的过程,他们之间的互相关系为异步;同步必须执行到底后能力执行其余操作,异步可同时执行。
多个线程执行的时候须要同步,如果是单线程则不须要同步。
2 异步实例
主办法和被调用的办法必须是不同的类,能力实现多线程。
2.1 启动类
应用@EnableAsync
来开启 SpringBoot 对于异步工作的反对。
Application:
@SpringBootApplication@EnableAsyncpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
2.2 线程池
配置类实现接口AsyncConfigurator,返回一个ThreadPoolTaskExecutor线程池对象。
config/AsyncConfig:
@Configuration@EnableAsyncpublic class AsyncConfig implements AsyncConfigurer { // ThredPoolTaskExcutor的解决流程 // 当池子大小小于corePoolSize,就新建线程,并解决申请 // 当池子大小等于corePoolSize,把申请放入workQueue中,池子里的闲暇线程就去workQueue中取工作并解决 // 当workQueue放不下工作时,就新建线程入池,并解决申请,如果池子大小撑到了maximumPoolSize,就用RejectedExecutionHandler来做回绝解决 // 当池子的线程数大于corePoolSize时,多余的线程会期待keepAliveTime长时间,如果无申请可解决就自行销毁 @Override @Bean public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 外围线程数:线程池创立的时候初始化的线程数 executor.setCorePoolSize(10); // 最大线程数:线程池最大的线程数,只有缓冲队列满了之后才会申请超过外围线程数的线程 executor.setMaxPoolSize(100); // 缓冲队列:用来缓冲执行工作的队列 executor.setQueueCapacity(50); // 线程池敞开:期待所有工作都实现再敞开 executor.setWaitForTasksToCompleteOnShutdown(true); // 等待时间:期待5秒后强制进行 executor.setAwaitTerminationSeconds(5); // 容许闲暇工夫:超过外围线程之外的线程达到60秒后会被销毁 executor.setKeepAliveSeconds(60); // 线程名称前缀 executor.setThreadNamePrefix("learn-Async-"); // 初始化线程 executor.initialize(); return executor; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return null; }}
2.3 controller
通过该层调用测试 Async。
@RestController@RequestMapping("/homepage")public class AsyncController { @Autowired AsyncService asyncTaskService; @GetMapping("/learnAsync") public String learnAsync(){ for (int i = 0; i < 10; i++) { asyncTaskService.executeAsyncTask(i); } return "1"; }}
2.4 service
通过@Async
注解表明该办法是异步办法,如果注解在类上,那表明这个类外面的所有办法都是异步的。
@Servicepublic class AsyncService { private final static Logger logger = LoggerFactory.getLogger(com.spring.boot.service.AsyncService.class); @Async // 表明该办法是异步办法。如果注解在类上,那表明类外面的所有办法都是异步 public void executeAsyncTask(int i) { logger.info("\t 实现工作" + i); System.out.println("线程" + Thread.currentThread().getName() + " 执行异步工作:" + i); }}
2.5 输入
3 Future 类
批改service层,别离应用同步调用、异步调用无返回、异步调用应用 Future 返回。
3.1 同步调用
public long subBySync() throws Exception { long start = System.currentTimeMillis(); long sum = 0; long end = System.currentTimeMillis(); sum = end - start; return sum;}
3.2 异步调用无返回
@Asyncpublic void subByVoid() throws Exception { long start = System.currentTimeMillis(); long sum = 0; long end = System.currentTimeMillis(); sum = end - start;}
3.3 异步调用 Future 返回
controller:
Future<Long> task = asyncTaskService.subByAsync();
service:
@Asyncpublic Future<Long> subByAsync() throws Exception { long start = System.currentTimeMillis(); long sum = 0; long end = System.currentTimeMillis(); sum = end - start; return new AsyncResult<>(sum);}
4 CompletableFuture 类
若应用 Future 呈现报错:
无奈判断org.springframework.scheduling.annotation.AsyncResult<>的类型参数
不存在类型变量V的实例,使org.springframework.scheduling.annotation.AsyncResult合乎XXX
能够应用 CompletableFuture 类:
@Asyncpublic CompletableFuture<Map<String, Object>> subByAsyncMap() throws Exception { Map<String, Object> res = new HashMap<>(); return CompletableFuture.completedFuture(res);}
5 线程敞开
当线程数量超过外围线程数量之后,运行结束的旧的线程会被敞开。
能够通过定时工作测试。
batch/ScheduledTaskService:
@Component@EnableSchedulingpublic class ScheduledTaskService { @Autowired AsyncService asyncService; @Scheduled(cron = "1/1 * * * * ? ") //1s一次 public void learnCron(){ asyncService.learnScheduledAsync(); }}
在 AsyncService 增加办法:
// 应用定时工作调用此办法创立线程@Asyncpublic void learnScheduledAsync(){ Long timeLong = System.currentTimeMillis(); SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //设置格局 String timeString = timeFormat.format(timeLong); System.out.println("线程" + Thread.currentThread().getName()); System.out.println("timeString:" + timeString + "\n");}
在异步配置(AsyncConfig)中已设置外围线程数为10:
// 外围线程数:线程池创立的时候初始化的线程数executor.setCorePoolSize(10);
运行能够察看输入,线程数达到10后会再一次从1开始。
学习更多编程常识,请关注我的公众号:
代码的路