Callable接口和Future接口

来源:互联网 发布:阴线买入公式源码 编辑:程序博客网 时间:2024/05/01 23:18

1.Callable和Future

Callable作用和Runnable类似,但是有返回值。对应Runnable接口的run方法,它有个call方法

V call()
       throws Exception

Future用于保存线程异步计算的结果,它最重要的方法是

V get()
      throws InterruptedException,
             ExecutionException

用于获取运算结果,它在调用时被阻塞,直到运算完成。可以被打断。

Future往往和Callable结合使用。

执行一个有返回值的任务步骤如下:

1.新建一个任务,实现Callable接口

2.用ExecutorService的submit方法提交任务

3.任务返回的计算结果是一个Future对象,调用Future对象的get获取结果

以下例子用线程池启动10个任务,并依次打印他们的返回值。

public class CallableDemo {public static void main(String[] args) {ExecutorService exec = Executors.newCachedThreadPool();ArrayList<Future<String>> results =new ArrayList<Future<String>>();for (int i = 0; i < 10; i++) {results.add(exec.submit(new TaskWithResult(i)));}for (Future<String> fs : results) {try {System.out.println(fs.get());} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}finally {exec.shutdown();}}}}class TaskWithResult implements Callable<String> {private int id;public TaskWithResult(int id) {this.id = id;}//有返回结果的方法@Overridepublic String call()  {return "result of TaskWithResult" + id;}}
输出:

result of TaskWithResult0
result of TaskWithResult1
result of TaskWithResult2
result of TaskWithResult3
result of TaskWithResult4
result of TaskWithResult5
result of TaskWithResult6
result of TaskWithResult7
result of TaskWithResult8
result of TaskWithResult9


2.FutureTask包装器

FutureTask可以将Callable转换成Future和Runnable,它同时实现了2个的接口:

public class FutureTask<V> implements RunnableFuture<V> 

public interface RunnableFuture<V> extends Runnable, Future<V>

以下的例子实现了统计指定目录下包含关键字的文件数目,

它用FutureTask对象包装一个Callable,启动任务进行统计,任务的call方法中采用递归的方式,遇到目录则再次启动一个线程,传入FutureTask包装的任务,获取运行的Future对象。如果遇到的是单个文件,则对文件进行统计。最后将所有统计结果(对于单个文件的count和目录的future list中的每个count)相加。

虽然get方法是阻塞的,但是在递归中启动了多个线程,其实他们是同时工作的,所以执行速度不会很慢。

public class FutureTest {public static void main(String[] args) throws Exception {Scanner in = new Scanner(System.in);System.out.print("输入目录:");String directory = in.nextLine();System.out.print("输入关键词:");String keyword = in.nextLine();MatchCounter counter = new MatchCounter(new File(directory), keyword);FutureTask<Integer> task = new FutureTask<Integer>(counter);ExecutorService executor = Executors.newSingleThreadExecutor();executor.execute(task);System.out.println("一共有"+ task.get() +"个匹配的文件");}}class MatchCounter implements Callable<Integer> {private File directory;private String keyword;private int count;public MatchCounter(File directory, String keyword) {this.directory = directory;this.keyword = keyword;}@Overridepublic 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()) {MatchCounter counter = new MatchCounter(file, keyword);FutureTask<Integer> task = new FutureTask<Integer>(counter);results.add(task);ExecutorService executor = Executors.newSingleThreadExecutor();executor.execute(task);} else {if (search(file)) {count++;}}}for (Future<Integer> result : results) {try {count += result.get();} catch (Exception e) {}}} catch (Exception e) {}return count;}public boolean search(File file) {try {Scanner inScanner = new Scanner(new FileInputStream(file));boolean found = false;while (!found && inScanner.hasNextLine()) {String line = inScanner.nextLine();if (line.contains(keyword)) {found = true;}}inScanner.close();return found;}catch (IOException e){return false;}}}
运行结果:

输入目录:F:/log
输入关键词:a
一共有1个匹配的文件