Callable和Future
Java1.5开始,Java提供了Callable接口,Callable接口提供了一个call()方法作为线程的执行体,但call()方法run()方法的功能更强大:
?call()方法可以有返回值
?call()方法可以声明抛出异常
因此我们完全可以提供一个Callable对象作为Thread的target,而该线程的执行体就是该Callable对象的call方法。问题是:Callable对象时JDK1.5开始新增的接口,而它并不是Runnable的子接口,所以Callable对象不能直接作为Thread的target,而且call方法有个返回值 ,call方法并不是直接调用,它是作为线程的执行体调用。那么如何获得call方法的返回值呢?
JDK1.5开始提供了一个Future接口来代表call方法的返回值,并未Future接口提供了一个FutureTask实现类,该实现类实现了Future接口,并实现了Runnable接口就可以Thread类的target接口了
Callable接口又泛型限制,Callable接口里的泛型形参类型与call方法的返回类型相同
在Future接口里定义了如下几个公共方法来控制它关联的Callable任务
?boolean cancel(boolean mayInterruptIfRunning):试图取消Future关联的Callable任务
?V get():返回Callable任务里call方法的返回值。调用该方法将导致程序阻塞必须等到,子线程结束时才会得到返回值
?V get(long timeout,TimeUnit unit):返回Callable任务里call方法的返回值,程序最多阻塞timeout和unit指定的时间,如果经过指定时间后还没有返回值就抛出TimeOutException
?boolean isCancelled():如果Callable任务正常完成前被取消则返回true
?boolean isDone():Callable任务完成则返回true
创建并启动有返回值的线程的步骤如下
1)创建Callable接口的实现类,实现call()方法,该call()方法作为线程的执行体,且该call()方法有返回值
2)创建Callable实现了的实例,使用FutureTask类来包装Callable对象,该FutureTask对象还封装了该Callable对象call()方法的返回值
3)使用FutureTask对象作为Thread实例的target创建并启动线程
4)调用FutureTask对象的方法来获得子线程结束后的返回值
再回首Java第二十四天
时间: 2024-10-29 19:09:02
再回首Java第二十四天的相关文章
再回首Java第二十六天
推回输入流在Java输入.输出流体系中有两个特殊的流与众不同,就是PushbackInputStream/PashbackReader,它们都提供了如下三个方法:?void unread(byte[]/char[] buf):将以一个字节/字符数组内容推回到推回缓冲区里,从而允许重复读取刚刚读取的内容.?void unread(byte[] /char[] buf, int off,int ben):把一个字节/字符数组从off开始,长度为len字节/字符的内容推回到推回缓冲区里,从而允许重复读
再回首Java第二十五天
流的分类按照流的流向来分,可以分为输入流和输出流?输入流:只能从中读取数据,不能向其写数据?输出流:只能向其写数据,不从能从中读数据 Java输入流主要有InputStream和Reader作为基类,Java输出流主要以OutputStream和Writer作为基类 字节流和字符流字节流和字符流的用法几乎完全一样,区别在于字节流和字符流所操作的数据单元不一样:字节流操作的最小数据单元是8位的字节,而字符流操作的最小数据单元是16位的字符 节点流和处理流可以从向一个特定的IO设备(如磁盘.网络)读
再回首Java第十四天
Calendar的实例方法setLenient(boolean bool)用于设置其容错性 Calendar两种的模式:lenient模式和no-lenient模式,当Calendar处于lenient模式时,每个时间字段可以接受超出它允许范围的值.当处于no-lenient模式时,当某个时间字段设置的值超出了它允许的范围,程序将抛出异常. set方法延迟修改 set(f,value)方法将日历字段f更改为value,此外它还设置了一个内部成员变量,以指示日历字段已被修改.尽管日历字段f是立即修
再回首Java第二十二天
类加载器的种类: 1.Bootstrap ClassLoader: 负责加载Java核心类,即$JAVA_HOME/jre/lib/rt.jar,由C++实现 2.Extension ClassLoader: 负责加载Java平台扩展功能的一些jar,包括$JAVA_HOME/jre/lib/*.jar和$JAVA_HOME/jre/lib/ext/*.jar 3.System(App) ClassLoader:负责加载classpath中指定的jar或.class 4.Custom Class
再回首Java第十五天
类的加载 当程序主动使用某个类是,如果该类还没有被加载到内存中,系统就会通过加载.链接.初始化三个步骤对该类进行初始化,如果没有意外,JVM就会完成这三个步骤,所以有时也把这三个步骤称为类的加载和类的初始化. 类的加载是指将类的class文件读入内存,并为之创建一个java.lang.Class对象,也就是说当程序中使用任何类时,系统都会为之创建一个java.lang.Class对象 类的加载由类的加载器完成,类加载器通常由JVM提供,这些类加载器是程序运行的基础,JVM提供的加载器其称为系统加
再回首Java第二十七天
泛型与数组 JDK1.5还有一个很重要的设计原则:如果一段代码在编译时系统没有产生:”unchecked未经检测的转换“,则程序在运行时不会引发”ClassCastException“异常.正是基于这个原因,所以数组元素的类型不能包含类型变量或类型形参,除非是无上限的类型通配符.但可以声明这样的数组,即使声明元素类型包含类型变量或类型形参的数组.也就是说:只能声明List<String>[]数组,但不能创建ArrayList<String>[10]这样的数组对象 假设Java能支持
再回首Java第二十三天
序列化版本问题由于反序列化Java对象时必须提供该对象的class文件,现在的问题是随着项目的升级,系统class文件也会升级,Java如何保证两个class文件的兼容性呢Java序列化机制允许为序列化类提供一个private static final 的serialVersionUID属性值,该属性用于该Java类的序列化版本,也就是说如果一个类升级后,只要它的serialVersionUID属性值保持不变,序列化机制也会把它们当成同一个序列化版本为了在反序列化时,确保序列化版本的兼容性,最好
再回首Java第十天
内部类 大部分时候,我们把类定义成一个独立的程序单元.在某些情况下,我们需要把一个类放在另一个类的内部定义,这个定义在其它类内部的类被称为内部类(嵌套类),包含内部类的类称为外部类(宿主类).内部类有如下作用 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同包的其它类访问.假设创建Cow这个类,需要组合CowLeg的属性,CowLeg属性只有在Cow类中有效,离开了Cow类就没有意义,这种情况下可以把CowLeg定义成Cow的内部类,不允许其它外部的类访问 内部类成员可以直接访问外
再回首Java第十九天
类加载机制 JVM的类加载机制主要有一下三种加载机制 全盘负责:所谓全盘负责就是说当一个类加载器负责加载某个Class的时候,该Class所依赖和引用的其它的Class都由该类加载器负责加载,除非显式使用另一个类加载器来载入 父类委托:所谓父类委托则是先让父类加载器试图加载该Class,只有在父类加载器无法加载时才从自己的类路径中加载该类 缓存机制:缓存机制保证所有被加载的Class都会被缓存,当程序中使用某个Class时,类加载器先从缓存中寻找该Class,只有当缓存中不存在该Class时,系