范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

异步编程Future掌控未来

  Callable
  有了Runnable,为什么还要Callable?
  我们先来看下Callable的接口:public interface Callable {     /**      * Computes a result, or throws an exception if unable to do so.      *      * @return computed result      * @throws Exception if unable to compute a result      */     V call() throws Exception; } 复制代码
  第一点是不能返回值,对于 Runnable 而言,它不能返回一个返回值,虽然可以利用其他的一些办法,比如在 Runnable 方法中写入日志文件或者修改某个共享的对象的办法,来达到保存线程执行结果的目的,但这种解决问题的行为千曲百折,属于曲线救国,效率着实不高。
  实际上,在很多情况下执行一个线程时,我们都希望能得到执行的任务的结果,也就是说,我们是需要得到返回值的,比如请求网络、查询数据库等。我们看接口中的V就代表返回值。
  第二点是不能抛异常,我们看下Callable接口定义的时候throw了Exception,而 Runnable是没有的,Runnable只能这样写,在里面try catch掉:Runnable runnable = new Runnable() {        /**         *  run方法上无法声明 throws 异常,且run方法内无法 throw 出 checked Exception,除非使用try catch进行处理         */        @Override        public void run() {            try {                throw new IOException();            } catch (IOException e) {                e.printStackTrace();            }        } } 复制代码
  最后对比一下Runnable和Callable方法名,Callable 规定的执行方法是 call(),而 Runnable 规定的执行方法是 run();返回值,Callable 的任务执行后有返回值,而 Runnable 的任务执行后是没有返回值的;抛出异常,call() 方法可抛出异常,而 run() 方法是不能抛出受检查异常的;和 Callable 配合的有一个 Future 类,通过 Future 可以了解任务执行情况,或者取消任务的执行,还可获取任务执行的结果,这些功能都是 Runnable 做不到的,Callable 的功能要比 Runnable 强大。Future
  下面就来介绍一下Future,上面说到Callable是可以返回值的,那这个返回值怎么拿呢?就是通过 Future 类的 get 方法来获取 。
  因此,Future 就相当于一个存储器,它存储了 Callable 的 call 方法的任务结果。除此之外,我们还可以通过 Future 的 isDone 方法来判断任务是否已经执行完毕了,还可以通过 cancel 方法取消这个任务,或限时获取任务的结果等,总之 Future 的功能比较丰富。
  如何创建Future
  一种是通过线程池,之前在讲线程池的时候也提到过, 《线程池源码精讲》   ExecutorService service = Executors.newFixedThreadPool(10);    Future future = service.submit(new CallableTask());    //阻塞获得结果    Integer rs = future.get(); 复制代码
  还有一种是通过FutureTask创建     FutureTask integerFutureTask = new FutureTask<>(new CallableTask());      //启动线程      new Thread(integerFutureTask).start();      //阻塞获得结果      Integer rs=integerFutureTask.get(); 复制代码
  有了宏观上的认识,我们来看下Future里面的方法:public interface Future {      boolean cancel(boolean mayInterruptIfRunning);      boolean isCancelled();      boolean isDone();      V get() throws InterruptedException, ExecutionException;      V get(long timeout, TimeUnit unit)          throws InterruptedException, ExecutionException, TimeoutException;  } 复制代码
  get() 方法最常见的就是当执行 get 的时候,任务已经执行完毕了,可以立刻返回,获取到任务执行的结果。任务还没有结果,如果任务还没开始或在进行中,我们去调用 get 的时候,都会把当前的线程阻塞,直到任务完成再把结果返回回来。任务执行过程中抛出异常,一旦这样,我们再去调用 get 的时候,就会抛出 ExecutionException 异常,不管我们执行 call 方法时里面抛出的异常类型是什么,在执行 get 方法时所获得的异常都是 ExecutionException。任务被取消了,如果任务被取消,我们用 get 方法去获取结果时则会抛出 CancellationException。任务超时, get 方法有一个重载方法,就是带延迟参数的,调用了这个带延迟参数的 get 方法之后,如果 call 方法在规定时间内正常顺利完成了任务,那么 get 会正常返回;但是如果到达了指定时间依然没有完成任务,get 方法则会抛出 TimeoutException,代表超时了。
  isDone() 方法
  该方法是用来判断当前这个任务是否执行完毕了。需要注意的是,这个方法如果返回 true,则代表执行完成了,如果返回 false 则代表还没完成。
  但这里如果返回 true,并不代表这个任务是成功执行的,比如说任务执行到一半抛出了异常。那么在这种情况下,对于这个 isDone 方法而言,它其实也是会返回 true 的,因为对它来说,虽然有异常发生了,但是这个任务在未来也不会再被执行,它确实已经执行完毕了。所以 isDone 方法在返回 true 的时候,不代表这个任务是成功执行的,只代表它执行完毕了。
  cancel()方法当任务还没有开始执行时,一旦调用 cancel,这个任务就会被正常取消,未来也不会被执行,那么 cancel 方法返回 true。如果任务已经完成,或者之前已经被取消过了,那么执行 cancel 方法则代表取消失败,返回 false。因为任务无论是已完成还是已经被取消过了,都不能再被取消了。当这个任务正在执行,这个时候执行 cancel 方法是不会直接取消这个任务的,而是会根据我们传入的参数做判断。cancel 方法是必须传入一个参数,该参数叫作 mayInterruptIfRunning,它是什么含义呢?如果传入的参数是 true,执行任务的线程就会收到一个中断的信号,正在执行的任务可能会有一些处理中断的逻辑,进而停止,这个比较好理解。如果传入的是 false 则代表不中断正在运行的任务,也就是说,本次 cancel 不会有任何效果,同时 cancel 方法会返回 false。
  isCancelled() 方法
  判断是否被取消,它和 cancel 方法配合使用,比较简单。
  下面看下FutureTask的类图:
  我们看了上面的代码其实也能猜到,既然 futureTask 能丢到 Thread 类里面去执行,那它肯定继承了Runnable接口,实现了run方法;既然能够调用get()方法,肯定是继承了Future接口,与上面的类图吻合。
  我们看下源码,看下run()方法,很简单,里面执行的逻辑就是Callable里面的call方法,最终将计算出来的结果保存到outcome里面去,然后唤醒阻塞的线程。
  看下get()方法,很简单,如果任务结束完成了,直接把outcome里的值返回,否则加入到阻塞队列,类似于AQS。《ReentrantLock介绍及AQS源码精讲》
  最后看下流程图:
  CompletableFuture
  上面介绍了Future/Callable的使用和原理,下面介绍下CompletableFuture。
  CompletableFuture对Future做了改进,主要是在get()方法上,主线程如果需要依赖该任务执行结果继续后续操作时,不再需要等待,而是可以直接传入一个回调对象,当异步任务执行完成后,自动调用该回调对象,相当于实现了异步回调通知功能。
  除此之外,CompletableFuture还提供了非常强大的功能,比如对于回调对象的执行,可以放到非任务线程中执行,也能用任务线程执行;提供了函数式编程能力,简化了异步编程的复杂性;提供了多个CompletableFuture的组合与转化功能。
  看下类图,实现了CompletionStage和Future接口。
  Future就是上面讲的Future,里面有5个方法。CompletionStage表示任务执行的一个阶段,每个异步任务都会返回一个新的CompletionStage对象,我们可以针对多个CompletionStage对象进行串行、并行或者聚合的方式来进行后续下一阶段的操作,简单来说,就是实现异步任务执行后的自动回调功能。CompletableFuture的构建
  CompletableFuture提供了四个静态方法来构建一个异步事件,方法如下。supplyAsync(Supplier supplier):带有返回值的异步执行方法,传入一个函数式接口,返回一个新的CompletableFuture对象。默认使用ForkJoinPool.commonPool()作为线程池执行异步任务。supplyAsync(Supplier supplier,Executor executor):带有返回值的异步执行方法,多了一个Executor参数,表示使用自定义线程池来执行任务。runAsync(Runnable runnable):不带返回值的异步执行方法,传入一个Runnable,返回一个新的CompletableFuture对象。默认使用ForkjoinPool.commonPool()作为线程池执行异步任务。runAsync(Runnable runnable,Executor executor):不带返回值的异步执行方法, 多了一个Executor参数,表示使用自定义线程池来执行任务。
  下面看下CompletableFuture的简单用法:public static void main(String[] args) throws ExecutionException, InterruptedException {     CompletableFuture cf1 = CompletableFuture.runAsync(() -> {         System.out.println(Thread.currentThread().getName() + ":异步执行一个任务");     });     //通过阻塞获取执行结果     System.out.println(cf1.get());       CompletableFuture cf2 = CompletableFuture.supplyAsync(() -> "Hello World").thenAccept(result -> {         System.out.println(result);     });     //继续做其他事情     //... } 复制代码
  cf1就是执行一个任务,用的是默认ForkJoinPool的线程池,不带返回值,cf1.get()是阻塞获取值,因为不带返回值,所以获取的是null。
  cf2是执行一个带返回值的任务,里面就干一件事return hello world,此时主线程可以继续往下执行做其他事情,待任务执行完以后,thenAccept方法接收到返回的hello world,然后打印出来。
  CompletableFuture方法介绍
  我们可以看下CompletableFuture类里面有38个方法,十分的多,下面和大家分类介绍一下。
  获取结果方法
  CompletableFuture类实现了Future接口,所以它开始可以像Future那样主动通过阻塞或者轮询的方式来获得执行结果。get(),基于阻塞的方式获取异步任务执行结果。get (long timeout, TimeUnit unit),通过带有超时时间的阻塞方式获取异步执行结果。join(),和 get() 方法的作用相同,唯一不同的点在于 get() 方法允许被中断,也就是会抛出InterruptedException ,但是join()不允许被中断。getNow(T valueIfAbsent),这个方法有点特殊,如果当前任务已经执行完成,则返回执行结果,否则返回传递进去的参数 valueIfAbsent 。
  在CompletableFuture类中还有一个比较有意思的方法 complete(T value) ,它表示完成完成计算, 也就是把 value 设置为CompletableFuture的返回值并且唤醒在上述方法阻塞的线程。
  我们看下下面的例子,就是创建两个线程t1和t2,线程里面通过completableFuture.get()方法阻塞,当我们调用cf.complete("Finish")方法的时候,相当于往里面赋值了,get()方法取到值了,才能继续往下走。public class CompleteExample {      static class ClientThread implements Runnable {          private CompletableFuture completableFuture;          public ClientThread(CompletableFuture completableFuture) {             this.completableFuture = completableFuture;         }          @Override         public void run() {             try {                 System.out.println(Thread.currentThread().getName() + ":" +                         completableFuture.get()); //阻塞             } catch (InterruptedException e) {                 e.printStackTrace();             } catch (ExecutionException e) {                 e.printStackTrace();             }         }      }      public static void main(String[] args) {         CompletableFuture cf = new CompletableFuture();         new Thread(new ClientThread(cf), "t1").start();         new Thread(new ClientThread(cf), "t2").start();         //执行某段逻辑         cf.complete("Finish");         //exception         //cf.completeExceptionally(e);     } } 复制代码
  纯消费类型的方法
  纯消费类型的方法,指依赖上一个异步任务的结果作为当前函数的参数进行下一步计算,它的特点是不返回新的计算值,这类的方法都包含 Accept 这个关键字。在CompletionStage中包含9个Accept关键字的方法,这9个方法又可以分为三类:依赖单个CompletionStage任务完成,依赖两个CompletionStage任务都完成,依赖两个CompletionStage中的任何一个完成。//当前线程同步执行 public CompletionStage thenAccept(Consumer<? super T> action); //使用ForkJoinPool.commonPool线程池执行action public CompletionStage thenAcceptAsync(Consumer<? super T> action); //使用自定义线程池执行action public CompletionStage thenAcceptAsync(Consumer<? super T> action,Executor executor); public  CompletionStage thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action); public  CompletionStage thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action); public  CompletionStage thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action,Executor executor); public CompletionStage acceptEither(CompletionStage<? extends T> other,Consumer<? super T> action); public CompletionStage acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action); public CompletionStage acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action,Executor executor); 复制代码
  thenAccept上面演示过了,下面演示下thenAcceptBoth() 方法,当task1和task2都返回值以后,然后再一起打印出来。public class AcceptExample {      public static void main(String[] args) throws ExecutionException, InterruptedException {          CompletableFuture task1 = CompletableFuture.supplyAsync(() -> "AcceptBot");         CompletableFuture task2 = CompletableFuture.supplyAsync(() -> "Message");          task1.thenAcceptBoth(task2, (r1, r2) -> {             System.out.println("result: " + r1 + r2);         });     }  } 复制代码
  有返回值类型的方法
  有返回值类型的方法,就是用上一个异步任务的执行结果进行下一步计算,并且会产生一个新的有返回值的CompletionStage对象。
  在CompletionStage中,定义了9个带有返回结果的方法,同样也可以分为三个类型:依赖单个CompletionStage任务完成,依赖两个CompletionStage任务都完成,依赖两个CompletionStage中的任何一个完成。public  CompletionStage thenApply(Function<? super T,? extends U> fn); public  CompletionStage thenApplyAsync(Function<? super T,? extends U> fn); public  CompletionStage thenApplyAsync(Function<? super T,? extends U> fn,Executor executor); public  CompletionStage thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn); public  CompletionStage thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn); public  CompletionStage thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn,Executor executor); public  CompletionStage applyToEither(CompletionStage<? extends T> other,Function<? super T, U> fn); public  CompletionStage applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn); public  CompletionStage applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn,Executor executor); 复制代码
  thenApply() 方法
  这新建一个任务return hello,thenApply在拿到值以后再和world拼接,然后再返回值,然后通过get获取到值。public class ApplyExample {      public static void main(String[] args) throws ExecutionException, InterruptedException {          CompletableFuture cf = CompletableFuture.supplyAsync(() -> "hello ").thenApply(r -> {             return r + "world";         });         System.out.println(cf.get());      }  } 复制代码
  thenCombineAsync() 方法
  thenCombineAsync的作用就是将task1和task2的值都拿到以后返回值。public class CombineDemo {      public static void main(String[] args) throws ExecutionException, InterruptedException {          CompletableFuture cf = CompletableFuture.supplyAsync(() -> "Combine")                 .thenCombineAsync(CompletableFuture.supplyAsync(() -> "Message"), (r1, r2) -> r1 + r2);         System.out.println(cf.get());     }  } 复制代码
  不消费也不返回的方法
  也是9个方法public CompletionStage thenRun(Runnable action); public CompletionStage thenRunAsync(Runnable action); public CompletionStage thenRunAsync(Runnable action,Executor executor); public CompletionStage runAfterBoth(CompletionStage<?> other,Runnable action); public CompletionStage runAfterBothAsync(CompletionStage<?> other,Runnable action); public CompletionStage runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor executor); public CompletionStage runAfterEither(CompletionStage<?> other,Runnable action); public CompletionStage runAfterEitherAsync(CompletionStage<?> other,Runnable action); public CompletionStage runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor); 复制代码
  这里新建两个任务,一个是return Both,一个是return Message,在都执行结束以后,因为run是不消费也不返回的,所以入参为0,不需要你们的参数,也不返回,所以没有return。public class RunExample {      public static void main(String[] args) throws ExecutionException, InterruptedException {         CompletableFuture cxf = CompletableFuture.supplyAsync(() -> "Both")                 .runAfterBoth(CompletableFuture.supplyAsync(() -> "Message"), () -> {                     System.out.println("Done");                 });         System.out.println(cxf.get());     }  } 复制代码
  多任务组合public  CompletionStage thenCompose(Function<? super T, ? extends CompletionStage> fn); public  CompletionStage thenComposeAsync(Function<? super T, ? extends CompletionStage> fn); public  CompletionStage thenComposeAsync(Function<? super T, ? extends CompletionStage> fn,Executor executor); 复制代码异常处理
  异常处理一共三个方法whenComplete:表示当任务执行完成后,会触发的方法,它的特点是,不论前置的CompletionStage任务是正常执行结束还是出现异常,都能够触发特定的 action 方法。handle:表示前置任务执行完成后,不管前置任务执行状态是正常还是异常,都会执行handle中的fn 函数,它和whenComplete的作用几乎一致,不同点在于,handle是一个有返回值类型的方法。exceptionally:接受一个 fn 函数,当上一个CompletionStage出现异常时,会把该异常作为参数传递到 fn 函数。
  这里写在一个例子里面,具体用哪种类型,小伙伴按照具体场景具体选取。
  最后CompletableFuture里面的方法十分的多,本文介绍了几个,抛砖引玉,更多的是小伙伴在实际开发过程中慢慢的用,熟能生巧,有些方法缺少应用场景也很难举出例子来,以及这些方法里面传的参数都是函数式接口,java8新特性lambda表达式,这个也是需要学会的,否则会看不懂。感谢收看~
  作者:小杰博士
  链接:https://juejin.cn/post/7035616558604877855
  来源:稀土掘金
  著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

远程轻松开机用电一目了然,向日葵智能插线板P1智慧生活新篇章智能插线板见多了,但是能远程开电脑远程控制电脑的智能插线板见过么?我这边就搞到了这样一款牛皮Plus的设备向日葵智能插线板P1计量版,今天就结合眼镜哥这段时间的使用体验,和大家一起微信有很多大家可能不知道的功能现在手机微信等娱乐平台,几乎让我们欲罢不能,有事没事都要看看手机,刷刷抖音,看看西瓜视频,看看今日头条!这里我只给大家介绍一个自己不认识的字怎么写岀来,其实微信就是一个字典,不用到红魔发布元宇宙概念红魔7将搭载骁龙8Gen1于2月发布今日红魔游戏手机正式宣布红魔元宇宙概念。官方宣布在2022年,将发挥核心技术优势,打造软硬协同VR生态体系,布局VR生态产品,打造属于红魔的元宇宙。努比亚技术有限公司高级副总裁余航卢伟冰嘲讽友商嗡嗡嗡立功了!X轴线性马达迎来巨大的技术升级没有竞争就没有进步,这句话在手机行业被体现的淋漓尽致,就以安卓手机为例,在各大安卓手机厂商的疯狂竞争下,安卓手机上的很多功能迎来了大跨越,包括屏幕相机快充等等可以说每一个功能都进步北汽刘宇Robotaxi带来的最大挑战在网约车上新京报贝壳财经讯(记者白昊天)1月20日,北汽集团副总经理刘宇在智驾碳新第十七届超级汽车论坛上表示,Robotaxi解决的是运营类车辆通过自动驾驶降低人工成本,提供便捷服务的方式,你们觉得最好的软件是什么?1。解决文件夹切换问题Clover原来为了完成一项工作,需要不断在各个文件夹之间切换费时费力,如果文件夹太多,还容易搞混。这款软件可以让文件夹切换和浏览器在各个网页间切换一样顺滑高有赞大裁员人员优化成今年OKR产品技术先走人副总裁陈锦晖离职钛媒体注本文来源于微信公众号新浪科技(IDtechsina),作者花子健,编辑韩大鹏,钛媒体经授权发布。有赞的确在裁员,不仅如此,高管也有离职,一位消息人士告诉新浪科技。2017年2021年度中国互联网辟谣优秀作品揭晓2021年度中国互联网辟谣优秀作品于2022年1月20日在京揭晓。本次优秀作品评选面向网络辟谣相关专栏专题系列产品专项活动等,新增了组织策划类奖项。质疑中国抗疫政策前,自己先照照镜华为Mate30只值700元?苹果降低安卓换购价值,网友质疑割韭菜苹果公司对购买iPhone手机推出换购计划,购买新机时回收老手机可享一定抵扣金额,可以更简单的理解为以旧换新补差价。只是苹果换购计划远低于市场行情,尤其安卓手机只给白菜价,甚至连正美国要求即时通信软件帮助美特工监控中国用户环球时报一边抹黑中国政府收集数据,一边却强制性要求美国企业监控中国用户据美国福布斯杂志网站17日报道,一份刚刚解密的美国政府监控申请显示,在没有出示任何正当理由的情况下,美国缉毒署命令行终端下载指令大全(winlinux)1。简介在我们渗透测试的过程中,通常会需要向目标主机传送一些文件,来达到提权,维持控制等目的。因此当不方便进行直接传输时,同时目标主机是能有网络连接的,那么此时就可以通过本地下载这
元宇宙的未来是怎样的?一众科创精英多维度解读21世纪经济报道记者张赛男上海报道元宇宙的火热引发了学界和业界的共同关注。1月16日,复旦大学管理学院2022瞰见对话科创人物开年首讲举办。本次论坛以庄周与梦蝶走进元宇宙的平行世界华为智慧屏V系列,越看越舒服,让孩子心甘情愿上网课一直以来,电视的发展都代表着整个时代科技的革新。从全村人挤在仅14寸的黑白电视前观看节目,到如今每家每户都用上了大尺寸的超薄液晶电视,你很难不去期待电视未来会变成什么样。机锋君今天三大运营商高速增长,提速降费前功尽弃?最近三大运营商都公布了一季度的经营报告。工信部的数据显示,在老大哥中国移动的直接带领下,三大运营商都实现了高速增长,行业平均增速为11。6,其中中国移动和中国电信的增速都超过了14华为这50倍放大拍照效果,你相信是手机能拍出来的吗?一组国外媒体的照片,华为P30说pro拍摄的看下放大后,远处的游船,清晰可见,这50倍效果有没有震惊到你?有人说我对拍照没有什么要求,这50倍焦段对我来说没什么用小编要说的是,用不比集五福更给力!今天,马云撒9亿红包雨,微信又被超越了长达19天的持久作战,今天,大家期待的支付宝9亿元大项目终于完成了。上个月初,为了刺激支付宝线下扫码消费,马云再次撒钱,推出到店付款19天,瓜分9亿,组队赢翻倍活动,只要在31天内谁将点燃第三次世界大战的战火?美国专家给出的答案截然不同本文章已经通过区块链技术进行版权认证,禁止任何形式的改编转载抄袭,违者追究法律责任第二次世界大战已经过去了很久,现在世界上也没有再发生如此大规模的战争了。但是我相信,有一件事大家一我国成功发射天链二号01星2019年3月31日23时51分,我国在西昌卫星发射中心用长征三号乙运载火箭,将天链二号01星送入太空,卫星成功进入地球同步轨道。天链二号01星是我国第二代数据中继卫星系统的第一颗扫雷都玩过,但是你知道扫雷的世界纪录有多快吗?每个人一定都接触过一种叫做扫雷的游戏,这是由微软设计师罗伯特德姆和卡特约翰逊于1981年设计的。许多人可能在几次尝试后就放弃了。毕竟,如果他们不理解游戏规则,即使这是最简单的难度,日薪1万元!要求会骑电瓶车!这则招聘让网友超激动我要暴富啦3月28日,菜鸟裹裹在微博发布了一则招聘信息日薪1万元,招募全民寄件服务体验官。具体要求都有啥?日薪1万元,只招3人,体验菜鸟裹裹快递员的工作。为寄件用户提供1小时上门取件的服务,刚刚,又一国产手机实力圈粉!来源财经要参一hr只做最屌的产品,只圈最硬的粉丝,只拼一个市场的生意!说起国产手机,你想到的都是哪些品牌?是搅翻欧洲市场的华为中兴,还是雄心勃勃进军海外市场的小米VIVO?跟这些手全球首个启用5G的国家,比中国还要快,难怪称华为是功臣先声夺人,科引潮流,先你所想。我是原创作者小枫说科技,专门为大家写一些自己的原创作品。随着现在互联网科技的发展,相信大家也是深有体会,在这种高速发展的社会,我们从中也能享受到科技带