Runnable封装一个异步运行的任务,没有参数没有返回值的异步方法。Callable和runnable类似,但是有返回值,callable接口是一个参数化的类型,只有一个方法call。参数类型是返回值类型。实际上该接口将运行产生一个结果的任务。
package java.util.concurrent;
public interface Callable<V> {
/**
* Computes a result
*
* @return computed result
*/
V call() throws Exception;
}
Future保存异步计算的结果,可以启动一个计算,将Future对象交给某个线程,然后忘掉它。Future对象的所有者在结果计算好之后就可以获得她。
Future接口具有以下方法:
package java.util.concurrent;
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;
}
调用get()方法被阻塞,知道计算完成,如果在计算完成之前,第二个方法的调用超时,抛出TimeoutException异常。如果计算已经完成,那么get()方法立即返回。
可以用cancel方法取消计算。
FutureTask包装器是一种非常便利的机制,可将Callable转换成Future和runnable,同时实现二者的接口。
Callable<Integer> mCall= ......;
FutureTask<Integer> task = new FutureTask<Integer>(mCall);
Thread t = new Thread(task);
t.start();
这是FutureTask的通常的使用方法
丛继承关系中分析:
FutureTask<V> implements RunnableFuture<V>
public interface RunnableFuture<V> extends Runnable, Future<V>
利用递归查询某个目录下包含某个关键字的文件的总数量.
package com.test.thread;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
/**
* 核心类,实现Callable接口,返回某目录下包含keyWord的文件的数量
* @author tony
*/
public class MatchCounter implements Callable<Integer>{
/**
* 路径
*/
private File directory;
/**
* 关键字
*/
private String keyWords;
/**
* 最终的返回结果
*/
private int count;
public MatchCounter(File directory, String keyWords) {
super();
this.directory = directory;
this.keyWords = keyWords;
}
@Override
public Integer call() throws Exception {
count = 0;
try {
File[] files = directory.listFiles();
ArrayList<Future<Integer>> results = new ArrayList<Future<Integer>>();
for (File file : files) {
if (file.isDirectory())
{
//如果该路径还有子路径,递归调用,每次遍历一个文件夹新开一个线程
//封装FutureTask<Integer>及时的获取到返回值
MatchCounter counter = new MatchCounter(file, keyWords);
FutureTask<Integer> task = new FutureTask<Integer>(counter);
results.add(task);
Thread t = new Thread(task);
t.start();
}
else
{
if (search(file)) {
count++;
}
}
}
for (Future<Integer> result : results) {
count+= result.get();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return count;
}
/**
* 判断该文件是否含有关键字keyword
* @param file
* @return
*/
public boolean search(File file){
try {
Scanner scanner = new Scanner(new FileInputStream(file));
boolean isFound = false;
while (!isFound && scanner.hasNextLine()) {
String line = scanner.nextLine();
if (line.contains(keyWords)) {
isFound = true;
}
}
return isFound;
} catch (IOException e) {
return false;
}
}
}
package com.test.thread;
import java.io.File;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class FutureTest {
public static void main(String[] args) {
MatchCounter counter = new MatchCounter(new File("C:\\Users\\tony\\git\\"), "view");
FutureTask<Integer> task = new FutureTask<Integer>(counter);
Thread thread = new Thread(task);
thread.start();
try {
System.out.println(task.get()+"matching files.");
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}