0
点赞
收藏
分享

微信扫一扫

并发编程之应用之异步调用案例的详细解析

应用之异步调用(案例) 需要等待结果 这时既可以使用同步处理,也可以使用异步来处理

join 实现(同步)

static int result = 0; private static void test1() throws InterruptedException { log.debug("开始"); Thread t1 = new Thread(() -> { log.debug("开始"); sleep(1); log.debug("结束"); result = 10; }, "t1"); t1.start(); t1.join(); log.debug("结果为:{}", result); } 一键获取完整项目代码 java

输出

20:30:40.453 [main] c.TestJoin - 开始 20:30:40.541 [Thread-0] c.TestJoin - 开始 20:30:41.543 [Thread-0] c.TestJoin - 结束 20:30:41.551 [main] c.TestJoin - 结果为:10 一键获取完整项目代码 java 评价

需要外部共享变量,不符合面向对象封装的思想

必须等待线程结束,不能配合线程池使用

Future 实现(同步) private static void test2() throws InterruptedException, ExecutionException { log.debug("开始"); FutureTask result = new FutureTask<>(() -> { log.debug("开始"); sleep(1); log.debug("结束"); return 10; }); new Thread(result, "t1").start(); log.debug("结果为:{}", result.get()); } 一键获取完整项目代码 java

输出

10:11:57.880 c.TestSync [main] - 开始 10:11:57.942 c.TestSync [t1] - 开始 10:11:58.943 c.TestSync [t1] - 结束 10:11:58.943 c.TestSync [main] - 结果为:10 一键获取完整项目代码 java 评价

规避了使用 join 之前的缺点

可以方便配合线程池使用

private static void test3() throws InterruptedException, ExecutionException { ExecutorService service = Executors.newFixedThreadPool(1); log.debug("开始"); Future result = service.submit(() -> { log.debug("开始"); sleep(1); log.debug("结束"); return 10; }); log.debug("结果为:{}, result 的类型:{}", result.get(), result.getClass()); service.shutdown(); } 一键获取完整项目代码 java

输出

10:17:40.090 c.TestSync [main] - 开始 10:17:40.150 c.TestSync [pool-1-thread-1] - 开始 10:17:41.151 c.TestSync [pool-1-thread-1] - 结束 10:17:41.151 c.TestSync [main] - 结果为:10, result 的类型:class java.util.concurrent.FutureTask 一键获取完整项目代码 java 评价

仍然是 main 线程接收结果

get 方法是让调用线程同步等待

自定义实现(同步) 见模式篇:保护性暂停模式

CompletableFuture 实现(异步) private static void test4() { // 进行计算的线程池 ExecutorService computeService = Executors.newFixedThreadPool(1); // 接收结果的线程池 ExecutorService resultService = Executors.newFixedThreadPool(1); log.debug("开始"); CompletableFuture.supplyAsync(() -> { log.debug("开始"); sleep(1); log.debug("结束"); return 10; }, computeService).thenAcceptAsync((result) -> { log.debug("结果为:{}", result); }, resultService); } 一键获取完整项目代码 java

输出

10:36:28.114 c.TestSync [main] - 开始 10:36:28.164 c.TestSync [pool-1-thread-1] - 开始 10:36:29.165 c.TestSync [pool-1-thread-1] - 结束 10:36:29.165 c.TestSync [pool-2-thread-1] - 结果为:10 一键获取完整项目代码 java 评价

可以让调用线程异步处理结果,实际是其他线程去同步等待

可以方便地分离不同职责的线程池

以任务为中心,而不是以线程为中心

BlockingQueue 实现(异步) private static void test6() { ExecutorService consumer = Executors.newFixedThreadPool(1); ExecutorService producer = Executors.newFixedThreadPool(1); BlockingQueue queue = new SynchronousQueue<>(); log.debug("开始"); producer.submit(() -> { log.debug("开始"); sleep(1); log.debug("结束"); try { queue.put(10); } catch (InterruptedException e) { e.printStackTrace(); } }); consumer.submit(() -> { try { Integer result = queue.take(); log.debug("结果为:{}", result); } catch (InterruptedException e) { e.printStackTrace(); } }); } 一键获取完整项目代码 java

不需等待结果 这时最好是使用异步来处理

普通线程实现 @Slf4j(topic = "c.FileReader") public class FileReader { public static void read(String filename) { int idx = filename.lastIndexOf(File.separator); String shortName = filename.substring(idx + 1); try (FileInputStream in = new FileInputStream(filename)) { long start = System.currentTimeMillis(); log.debug("read [{}] start ...", shortName); byte[] buf = new byte[1024]; int n = -1; do { n = in.read(buf); } while (n != -1); long end = System.currentTimeMillis(); log.debug("read [{}] end ... cost: {} ms", shortName, end - start); } catch (IOException e) { e.printStackTrace(); } } } 一键获取完整项目代码 java

没有用线程时,方法的调用是同步的:

@Slf4j(topic = "c.Sync") public class Sync { public static void main(String[] args) { String fullPath = "E:\\1.mp4"; FileReader.read(fullPath); log.debug("do other things ..."); } } 一键获取完整项目代码 java 输出

18:39:15 [main] c.FileReader - read [1.mp4] start ... 18:39:19 [main] c.FileReader - read [1.mp4] end ... cost: 4090 ms 18:39:19 [main] c.Sync - do other things ... 一键获取完整项目代码 java 使用了线程后,方法的调用时异步的:

private static void test1() { new Thread(() -> FileReader.read(Constants.MP4_FULL_PATH)).start(); log.debug("do other things ..."); } 一键获取完整项目代码 java 输出

18:41:53 [main] c.Async - do other things ... 18:41:53 [Thread-0] c.FileReader - read [1.mp4] start ... 18:41:57 [Thread-0] c.FileReader - read [1.mp4] end ... cost: 4197 ms 一键获取完整项目代码 java 线程池实现 private static void test2() { ExecutorService service = Executors.newFixedThreadPool(1); service.execute(() -> FileReader.read(Constants.MP4_FULL_PATH)); log.debug("do other things ..."); service.shutdown(); } 一键获取完整项目代码 java 输出

11:03:31.245 c.TestAsyc [main] - do other things ... 11:03:31.245 c.FileReader [pool-1-thread-1] - read [1.mp4] start ... 11:03:33.479 c.FileReader [pool-1-thread-1] - read [1.mp4] end ... cost: 2235 ms 一键获取完整项目代码 java CompletableFuture 实现 private static void test3() throws IOException { CompletableFuture.runAsync(() -> FileReader.read(Constants.MP4_FULL_PATH)); log.debug("do other things ..."); System.in.read(); } 一键获取完整项目代码 java 输出

11:09:38.145 c.TestAsyc [main] - do other things ... 11:09:38.145 c.FileReader [ForkJoinPool.commonPool-worker-1] - read [1.mp4] start ... 11:09:40.514 c.FileReader [ForkJoinPool.commonPool-worker-1] - read [1.mp4] end ... cost: 2369 ms 一键获取完整项目代码 java 以调用方角度来讲,

如果 需要等待结果返回,才能继续运行就是同步

不需要等待结果返回,就能继续运行就是异步

1.设计

多线程可以让方法执行变为异步的(即不要巴巴干等着)、比如说读取磁盘文件时,假设读取操作花费了 5 秒钟,如果没有线程调度机制,这 5 秒 cpu 什么都做不了,其它代码都得暂停...

2.结论

比如在项目中,视频文件需要转换格式等操作比较费时,这时开一个新线程处理视频转换,避免阻塞主线程

tomcat 的异步 servlet 也是类似的目的,让用户线程处理耗时较长的操作,避免阻塞 tomcat 的工作线程

ui 程序中,开线程进行其他操作,避免阻塞 ui 线程 ———————————————— 版权声明:本文为CSDN博主「向着五星的方向」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_69748833/article/details/136694577

举报
0 条评论