Java线程和多线程(十三)——Callable,Future,FutureTask
在Java多线程之中,Callable
和Future
的使用时非常广泛的。在之前的文章中,我们了解了关于Java线程池基础的一些内容,知道如何提交Runnable
的任务。但是,Runnable
的任务是无法有返回值,也不能抛出异常的。而有些时候,我们希望一个线程能够有一些返回值。在Java 5中,引入了java.util.concurrent.Callable
接口,这个接口很类似于Runnable
接口,但是可以返回一个对象,或者抛出异常。
Java Callable
Java的Callable
接口使用了泛型来定义返回的对象的类型。Executors
类提供了一些很实用的方法来在线程池中执行Callable
的任务。因为Callable
的任务通过并行的方式来运行,所以我们需要等待返回的对象。
public interface Callable<V> {
/**
* 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;
}
Java Future
Java的Callable
对象返回的就是java.util.concurrent.Future
对象。通过使用Java Future
对象,我们可以知道Callable
任务的执行状态,并且获得返回的对象。Future
接口提供get()
方法来让开发者可以等待Callable
任务的执行,然后获得对应的结果。
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
Java Future提供了一个cancel()
方法来取消关联的Callable
任务的执行。其中的get()
方法是包含一个重载的方法的,我们可以指定等待的时间,而不需要无限期的等待Callable
任务的执行。这个方法可以有效的防止一个线程的无限期的阻塞。
Future
也提供一个isDone()
和一个isCancelled()
方法来找到其关联的Callable
任务的执行状态。
下面是使用Callable
的例子,是在一秒之后返回执行任务的名字。我们通过使用Executor
框架来并行执行100个任务,然后用Future
来获得任务的执行结果。
package com.sapphire.threads;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(1000);
//return the thread name executing this callable task
return Thread.currentThread().getName();
}
public static void main(String args[]){
//Get ExecutorService from Executors utility class, thread pool size is 10
ExecutorService executor = Executors.newFixedThreadPool(10);
//create a list to hold the Future object associated with Callable
List<Future<String>> list = new ArrayList<Future<String>>();
//Create MyCallable instance
Callable<String> callable = new MyCallable();
for(int i=0; i< 100; i++){
//submit Callable tasks to be executed by thread pool
Future<String> future = executor.submit(callable);
//add Future to the list, we can get return value using Future
list.add(future);
}
for(Future<String> fut : list){
try {
//print the return value of Future, notice the output delay in console
// because Future.get() waits for task to get completed
System.out.println(new Date()+ "::"+fut.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
//shut down the executor service now
executor.shutdown();
}
}
当我们运行上面程序的时候,我们的输出会有延迟,因为Future的get()
方法会一直等待Callable
的任务执行完毕。同时需要注意的是,线程池中,我们仅仅会有10个线程来处理之前定义的Callable
任务。
下面是上面程序的输出结果:
Mon Dec 31 20:40:15 PST 2012::pool-1-thread-1
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-3
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-4
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-5
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-6
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-7
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-8
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-9
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-10
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
...
当我们想要覆盖掉
Future
接口的一些行为的时候,举例来说,假设我们需要覆盖其中的get()
方法来做一些超时处理而不进行持续等待等操作的时候。Java中的FutureTask
类在这种时候就会非常有用了,它是Future
接口的实现类。
FutureTask
在上面,我们了解到使用Callable
以及Future
接口来处理多线程的一些便利之处。
而FutureTask
是Future
接口的一个基础实现,并且提供了异步处理的功能,FutureTask
包含了一些方法来启动或者取消任务,也包含一些方法来返回Future
的状态,来确认Future
是完成了还是去掉了。我们需要一个Callable
对象来创建一个FutureTask
然后,我们可以通过ThreadPoolExecutor
来异步处理这些任务。
下面是FutureTask
的代码举例,因为FutureTask
是需要Callable
的,所以我们来创建一个Callable
的实现:
package com.sapphire.threads;
import java.util.concurrent.Callable;
public class MyCallable implements Callable<String> {
private long waitTime;
public MyCallable(int timeInMillis){
this.waitTime=timeInMillis;
}
@Override
public String call() throws Exception {
Thread.sleep(waitTime);
//return the thread name executing this callable task
return Thread.currentThread().getName();
}
}
下面是一个FutureTask
方法的例子,下面展示的是关于使用FutureTask
方法的一些举例:
package com.sapphire.threads;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class FutureTaskExample {
public static void main(String[] args) {
MyCallable callable1 = new MyCallable(1000);
MyCallable callable2 = new MyCallable(2000);
FutureTask<String> futureTask1 = new FutureTask<String>(callable1);
FutureTask<String> futureTask2 = new FutureTask<String>(callable2);
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(futureTask1);
executor.execute(futureTask2);
while (true) {
try {
if(futureTask1.isDone() && futureTask2.isDone()){
System.out.println("Done");
//shut down executor service
executor.shutdown();
return;
}
if(!futureTask1.isDone()){
//wait indefinitely for future task to complete
System.out.println(
"FutureTask1 output="+futureTask1.get());
}
System.out.println("Waiting for FutureTask2 to complete");
String s = futureTask2.get(200L, TimeUnit.MILLISECONDS);
if(s !=null){
System.out.println("FutureTask2 output="+s);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}catch(TimeoutException e){
//do nothing
}
}
}
}
当我们运行上面的程序,你会发现,有一段时间是不会输出任何东西到控制台的,因为FutureTask
的get()
方法会等待任务的完成,然后才会返回输出的对象。在FutureTask
中也有一个重载的方法会等待指定的时间。需要注意的是,当调用isDone()
方法来确定程序一旦结束,任务也会完成。
输出如下:
FutureTask1 output=pool-1-thread-1
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
FutureTask2 output=pool-1-thread-2
Done
从上面的例子来说是没有使用到FutureTask
的便利之处的,但是当我们想要覆盖掉Future
接口方法的实现,而不像实现Future
接口的每一个方法的时候,我们就可以考虑使用FutureTask
。
Java线程和多线程(十三)——Callable,Future,FutureTask的更多相关文章
- Java多线程:Callable,Future,FutureTask
一.Future Future和Callable基本是成对出现的,Callable负责产生结果,Future负责获取结果. 1.Callable接口类似于Runnable,只是Runnable ...
- Java 并发编程——Callable+Future+FutureTask
Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...
- Java并发编程:ThreadPoolExecutor + Callable + Future(FutureTask) 探知线程的执行状况
如题 (总结要点) 使用ThreadPoolExecutor来创建线程,使用Callable + Future 来执行并探知线程执行情况: V get (long timeout, TimeUnit ...
- java 并发runable,callable,future,futureTask
转载自:http://www.cnblogs.com/dolphin0520/p/3949310.html package future_call; import java.util.concurre ...
- JAVA线程池中的Callable和Future
import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.Completio ...
- Java多线程的Callable, Future, FutureCallback
Callable可以看成是一个增强版的Runnable, 带返回结果, 需要通过Future或者FutureTask来提交任务或运行线程, 然后通过Future/FutureTask的get方法得到返 ...
- Java线程与多线程教程
本文由 ImportNew - liken 翻译自 Journaldev. Java线程是执行某些任务的轻量级进程.Java通过Thread类提供多线程支持,应用可以创建并发执行的多个线程. 应用 ...
- Java 线程与多线程
Java是一门支持多线程的编程语言! 什么是进程? 计算机中内存.处理器.IO等资源操作都要为进程进行服务. 一个进程上可以创建多个线程,线程比进程更快的处理单元,而且所占用的资源也小,多线程的应用也 ...
- 12 Callable & Future & FutureTask
创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果. 如果需要获取执行结果,就必须通过共享变量或者使用 ...
随机推荐
- 从 Swift 中的序列到类型擦除
如果有这样的一个需求,我希望能像数组一样,用 for 循环遍历一个类或结构体中的所有属性.就像下面这样: let persion = Persion() for i in persion { prin ...
- pip-修改为国内镜像源
pip 常用命令 pip install ./downloads/SomePackage-1.0.4.tar.gz pip install http://my.package.repo/SomePac ...
- kendo ui - grid 数据表格系列
kendo-ui 官网:https://www.telerik.com/documentation 初始化 grid: 引入文件: <link rel="stylesheet" ...
- java从字符串中提取数字的简单实例
随便给你一个含有数字的字符串,比如: String s="eert343dfg56756dtry66fggg89dfgf"; 那我们如何把其中的数字提取出来呢?大致有以下几种方法, ...
- PHP文档
http://php.net/manual/zh/function.socket-close.php
- Spring @Value 默认值
@Value(value = "${etl.maxthreadcount:3}") private long MaxThreadCount;
- python codecs模块 ---处理数据写入文件时会有编码不统一的问题
我们用open方法打开文件有时候会有一些问题,因为open打开文件只能写入str类型,而不会管字符串是什么编码方式. 示例: >>> fr = open('test.txt','a' ...
- 理解numpy exp函数
exp,高等数学里以自然常数e为底的指数函数 Exp:返回e的n次方,e是一个常数为2.71828 Exp 函数 返回 e(自然对数的底)的幂次方. a = 1 print np.exp(a) a ...
- Android之zip文件加密解压及进度条的实现
zip文件的解压能够使用java的zip库,可是没有实现对加密文件的解压功能,这里能够使用zip4j来实现.详细能够參看该文<Android下zip压缩文件加密解密的完美解决方式>.该文件 ...
- 使用interface与类型诊断机制判断一个类型是否实现了某个方法
Golang中的interface通常用来定义接口,在接口里提供一些方法,其他类型可以实现(implement)这些方法,通过将接口指针指向不同的类型实例实现多态(polymorphism),这是in ...