栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java并发包学习3

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java并发包学习3

5:Future和Callable的使用

在JDK1.5的并发包可以使用Future和Callable来使线程具有返回值的功能。

Callable与Runnable的主要区别:

  • Callable接口的call()方法可以有返回值,而Runnable的run()没有。
  • call()方法可以声明抛出异常,而run()方法不能。
5.1.:Callable的简单使用


5.2: get()和sumbit()方法的使用

1、 get()方法:

  • get()方法是具有阻塞特性的,它可以结合future中的isDone()方法来搭配使用,isDone()是判断future中的线程是否完成。
  • get(long timeout,TimeUnit unit): 在指定的时间内等待获得返回值,如果在指定时间内没有获取到则抛出异常。

2、submit()方法:

  • submit不仅可以传入Callable还可以传入Runnable,说明它支持有返回值和无返回值的功能,如果没有返回值的话它输出null。
  • submit(Runnable,T result): 第二个参数result可以作为执行结果的返回值,而不需要使用get()方法来获取,即将result作为默认返回值返回。
  • 与execute()的区别: execute()没有返回值,默认遇到异常直接抛出,但可以通过自定义线程工厂来捕获,而submit()可以使用try/catch来捕获异常。


5.3:其他API的使用


  • cancel(boolean mayInterruptIfRunning): 参数的作用是如果线程正在运行是否中断,在代码中需要使用if(Thread.currentThread().isInterrupted()==true)进行搭配。返回值是发送取消命令是否成功完成(而不是线程是否中断成功),如果线程本身已经结束了,在发送cancel来取消线程,则返回false。
  • isCancelled():线程是否取消。
  • 它可以与之前的线程池那样可以定制线程工厂与自定义拒绝策略。
5.4:Future的缺点

调用get()方法时是阻塞的,一旦前面先行的任务耗时很多,后面的任务调用get()则一直要阻塞,大大影响效率。

6:CompletionService的使用

它的功能是以异步的方式一边生产新的任务,一边处理已完成的任务的结果。使用sumbit提交任务,使用take取得已完成的任务,并按照完成的时间顺序处理结果。
它的实现结构:

6.1:CompletionService的常用方法:


常用方法解析:


方法Poll(long timeout ,TimeUnit unit)的实验:

6.2:CompletionService与异常


第一种情况:不使用get方法,不出现异常


第二种:使用get,B出现异常,A顺利执行。


第三种如果执行顺序为先执行B,再执行A,则他们的结果都不能输出。

7:ExecutorService的使用


7.1.1: invokeAny的使用介绍


补充: 该方法具有阻塞特性,它会等待取得第一个完成任务的值,当第一个任务执行后,会调用interrupt()来将其他任务打断,其他任务可以结合if(Thread.currentThread().isInterrupted()==true)代码来决定线程是否继续执行下去。如果再上面if判断内的代码,使用的是throws new InterruptException来中断线程,虽然异常成功抛出,但是在main线程中是不会捕获它的。要想捕获异常,需在Callable中使用try/catch来进行捕获。

7.1.2:invokeAny与异常

假设A是执行较快的线程,B是执行较慢的线程

1、B出现异常: 主线程成功取得A的返回值,B出现异常,默认情况下不会在控制台打印异常信息,如果使用try/catch捕获异常则可以打印异常信息。
2、A出现异常: 默认不打印异常信息,等待B任务完成。A出现异常不影响B任务的取值,原理是源代码中一直在判断有没有正确的返回值。如果A任务捕获了异常,但没有用throws重新抛出,则主线程不会取得B结果值,因为A没有向主线程上报异常信息,主线程认为A是正确的,所以并不会把关注点放在B上。
3、A,B都出现异常: 最终的异常出现在B上。

总结:使用invokeAny方法的某一个任务正确执行,则其他Callable抛出的异常并不处理。 都没有正确返回值,则处理最后被抛出的异常。

7.1.3:异常情况的验证

B出现异常


A出现异常

A,B都出现异常

A出现异常捕获了,但未上报,B不出现异常


使用catch捕获了异常,有了打印信息,但是没有再次抛出,使得主线程认为A的返回结果是正确的,使用了A的结果。

如果将A中注释的抛出异常代码正常执行得到的结果是:

7.2.invokeAll方法的使用 7.2.1:invokeAll方法介绍

它会返回所有任务的执行结果,并且具有阻塞特性,要把所有结果都取回才继续向下执行。它与invokeAny并一样,它可以捕获Callable抛出的异常。

7.2.2:invokeAll与异常

invokeAll异常情况与快慢并无太大的关系,因为它返回的是个Future数组,如果你在得到Future数组之后,并未使用get方法去取任务的返回值,则主线程不会出现异常。而出现了异常则说明你在此时使用了返回结果不正确的Future的get()方法。
例如:线程A出现异常(Callable代码跟上一节一样)

7.2.3 invoke方法加入超时参数

invokeAll​(Collection tasks, long timeout, TimeUnit unit)作用是如果全部任务没有在指定时间内完成,则出现异常。
在上节代码的基础上仅修改invoke方法:


结果没有发生改变,说明即使是错误的返回结果,invoke方法仍认为它是成功返回的。

一个超时,一个不超时打印结果
将A出现异常的代码注释掉

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/287905.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号