-
普通線程實(shí)現(xiàn)異步,但頻繁創(chuàng)建、銷毀線程比較耗資源,所以一般交給線程池執(zhí)行
//創(chuàng)建需要異步執(zhí)行的邏輯 public class AsyncThread implements Runnable{ @Override public void run() { System.out.println("異步線程開始"); long start = System.currentTimeMillis(); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { throw new RuntimeException(e); } long end = System.currentTimeMillis(); System.out.println("異步線程:" + Thread.currentThread().getName() + "結(jié)束,耗時(shí):" + (end - start)); } } //在業(yè)務(wù)中進(jìn)行調(diào)用 @GetMapping("/thread") public String asyncThread(){ ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3, 3, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10), new ThreadPoolExecutor.AbortPolicy()); long start = System.currentTimeMillis(); //自己的業(yè)務(wù)代碼。。。 AsyncThread asyncThread = new AsyncThread(); threadPool.execute(asyncThread); long end = System.currentTimeMillis(); return "返回,耗時(shí):" + (end - start); }
結(jié)果:
-
Future異步
和普通線程實(shí)現(xiàn)異步區(qū)別不大,只是使用Future是要獲取執(zhí)行后的返回值
//創(chuàng)建具有返回值的任務(wù) public class CallableThread implements Callable { @Override public String call() throws Exception { long start = System.currentTimeMillis(); StopWatch stopWatch = new StopWatch(); stopWatch.start(); System.out.println("callable任務(wù)開始執(zhí)行:" + start); TimeUnit.SECONDS.sleep(2); System.out.println(); stopWatch.stop(); System.out.println("stopWatch.prettyPrint------"); System.out.println(stopWatch.prettyPrint()); System.out.println("stopWatch.shortSummary------"); System.out.println(stopWatch.shortSummary()); System.out.println("stopWatch.getTotalTimeMillis------"); System.out.println(stopWatch.getTotalTimeMillis()); return "call執(zhí)行結(jié)束 "; } } //在業(yè)務(wù)中進(jìn)行調(diào)用 public String threadFuture(){ ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3, 3, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10), new ThreadPoolExecutor.AbortPolicy()); long start = System.currentTimeMillis(); CallableThread callableThread = new CallableThread(); Future<String> submit = threadPool.submit(callableThread); try { //在獲取返回值時(shí)會(huì)阻塞主線程 String s = ""; s = submit.get(); System.out.println(s); } catch (Exception e) { System.out.println("線程運(yùn)行發(fā)生錯(cuò)誤" + e.getMessage()); throw new RuntimeException(e); } long end = System.currentTimeMillis(); return "接口返回,耗時(shí):" + (end - start); }
結(jié)果:
-
Spring的@Async異步
-
使用@Async注解實(shí)現(xiàn)異步的前提是需要在啟動(dòng)類上標(biāo)注@EnableAsync來開啟異步配置
-
配置線程池(@Async默認(rèn)情況下用的是SimpleAsyncTaskExecutor線程池,該線程池不是真正意義上的線程池,使用此線程池?zé)o法實(shí)現(xiàn)線程重用,每次調(diào)用都會(huì)新建一條線程。若系統(tǒng)中不斷的創(chuàng)建線程,最終會(huì)導(dǎo)致系統(tǒng)占用內(nèi)存過高,引發(fā)OutOfMemoryError錯(cuò)誤)
/** * 線程池配置,可以配置多個(gè)線程池 * @Async注解,默認(rèn)使用系統(tǒng)自定義線程池,可在項(xiàng)目中設(shè)置多個(gè)線程池,在異步調(diào)用的時(shí)候,指明需要調(diào)用的線程池名稱 * 比如:@Async("線程池1") */ @Configuration public class ExecutorConfig { /** * 自定義線程池 */ @Bean("myExecutor") public Executor taskExecutor(){ System.out.println("系統(tǒng)最大線程數(shù):" + Runtime.getRuntime().availableProcessors()); ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); threadPoolTaskExecutor.setCorePoolSize(8);//核心線程數(shù) threadPoolTaskExecutor.setMaxPoolSize(16);//最大線程數(shù) threadPoolTaskExecutor.setQueueCapacity(1000);//配置隊(duì)列容量 threadPoolTaskExecutor.setKeepAliveSeconds(60);//空閑線程存活時(shí)間 threadPoolTaskExecutor.setThreadNamePrefix("myExecutor-");//線程名字前綴 return threadPoolTaskExecutor; } }
-
編寫異步方法的邏輯,異步方法所在的類需要被Spring管理
@Service public class AsyncServiceImpl implements AsyncService { @Override @Async("myExecutor") public void sendMsg() { System.out.println("進(jìn)入異步方法"); System.out.println("當(dāng)前線程名稱:" + Thread.currentThread().getName()); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("異步方法執(zhí)行完成"); } /** * 具有返回值的異步方法,返回類型為Future,返回時(shí)new 一個(gè)AsyncResult對(duì)象,其中參數(shù)為返回的內(nèi)容 * @return */ @Override @Async("myExecutor") public Future<String> sendMsgFuture() { System.out.println("進(jìn)入future異步方法"); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { throw new RuntimeException(e); } return new AsyncResult<>("future異步方法執(zhí)行完成"); } }
-
在業(yè)務(wù)邏輯中調(diào)用
@GetMapping("/asyncMethod") public String asyncMethod(){ System.out.println("aaa"); System.out.println("調(diào)用異步方法"); asyncService.sendMsg(); System.out.println("bbb"); return "asyncMethod方法返回"; }
調(diào)用沒有返回值的異步方法結(jié)果:
@GetMapping("/asyncFutureMethod") public String asyncFutureMethod(){ System.out.println("aaa"); Future<String> stringFuture = asyncService.sendMsgFuture(); System.out.println("bbb"); try { System.out.println(stringFuture.get());//get方法會(huì)阻塞主線程 } catch (Exception e) { throw new RuntimeException(e); } return "asyncfutureMethod方法返回"; }
調(diào)用有返回值的異步方法結(jié)果:
-
-
Spring的ApplicationEvent事件實(shí)現(xiàn)異步
-
定義事件,繼承ApplicationEvent類
public class MessageEvent extends ApplicationEvent { @Getter private String message; public MessageEvent(Object source, String message) { super(source); this.message = message; } }
-
定義監(jiān)聽器(需要被Spring管理)
使用@EventListener注解寫在方法上定義一個(gè)監(jiān)聽器,即事件被觸發(fā)時(shí)執(zhí)行的方法(默認(rèn)是同步執(zhí)行,可以使用@Async注解標(biāo)注為異步執(zhí)行),支持多個(gè)監(jiān)聽器監(jiān)聽同一個(gè)事件。
@Component public class MessageEventHandler { //@Async @EventListener public void handleLoginEvent(LoginEvent event){ System.out.println("接受到LoginEvent事件"); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(event.getUsername()); System.out.println("LoginEvent事件處理完成"); } //@Async @EventListener public void handleMessageEvent(MessageEvent event){ System.out.println("接受到MessageEvent事件"); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(event.getMessage()); System.out.println("MessageEvent事件處理完成"); } }
-
定義事件發(fā)布者(觸發(fā)事件的)(需要被Spring管理)
實(shí)現(xiàn)ApplicationEventPublisherAware接口
@Component public class EventPublisher implements ApplicationEventPublisherAware { private ApplicationEventPublisher publisher; @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.publisher = applicationEventPublisher; } public void publish(ApplicationEvent event){ if (event instanceof MessageEvent){ System.out.println("開始發(fā)布MessageEvent事件:" + ((MessageEvent) event).getMessage()); } else if (event instanceof LoginEvent) { System.out.println("開始發(fā)布LoginEvent事件:" + ((LoginEvent) event).getUsername()); } //發(fā)布事件 publisher.publishEvent(event); System.out.println("事件發(fā)布結(jié)束"); } }
-
業(yè)務(wù)代碼執(zhí)行時(shí)觸發(fā)事件
@GetMapping("/pubEvent") public String publishEvent(){ System.out.println("業(yè)務(wù)邏輯開始"); eventPublisher.publish(new MessageEvent(this,"testEvent")); System.out.println("業(yè)務(wù)邏輯結(jié)束"); return "發(fā)布成功"; }
執(zhí)行結(jié)果:
由控制臺(tái)打印可以發(fā)現(xiàn)現(xiàn)在事件監(jiān)聽器方法的執(zhí)行是同步的,如果需要異步執(zhí)行,在監(jiān)聽器方法上加個(gè)@Async注解即可,但使用Async注解的前提是在啟動(dòng)類上標(biāo)注@EnableAsync注解來開啟異步配置
使用@Async注解后執(zhí)行結(jié)果:
文章來源:http://www.zghlxwxcb.cn/news/detail-759990.html
可以看到監(jiān)聽器中的打印在最后了,證明是異步執(zhí)行的文章來源地址http://www.zghlxwxcb.cn/news/detail-759990.html
-
到了這里,關(guān)于Java實(shí)現(xiàn)異步的幾種方式的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!