Java的多线程之Callable与Future

来源:互联网 发布:unity3d海底效果包 编辑:程序博客网 时间:2024/04/28 17:11

一、Callable与Future

       Runnable封装了一个异步运行的任务,可以把它想象成为一个没有参数和返回值的异步方法。Callable与Runnable类似,但是有返回值。Callable接口是一个参数化的类型,只有一个方法call。

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;}

       类型参数是返回值的类型。

       Future保存异步计算的结果。可以启动一个计算,将Future对象交给某个线程,然后忘掉它。Future对象的所有者在结果计算好之后就可以获得它。

       Future接口具有下面方法:

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异常。如果运行该计算的线程被中断,两个方法都将抛出InterruptedException。如果计算已经完成,那么get方法立即返回。

       如果计算还在进行,isDone方法返回false;如果完成了,则返回true。

       可以用cancel方法取消该计算。如果计算还没有开始,它被取消且不再开始。如果计算处于运行之中,那么如果mayInterrupt参数为true,它被中断。

       FutureTask包装器是一种非常便利的机制,可将Callable转换成Future和Runnable,它同时实现两者的接口。

例如:

Callable<Integer> myComputation = ...;FutureTask<Integer> task = new FutureTask<>(myComputation);Thread t = new Thread(task); //it's a Runnablet.start();...Integer result = task.get(); //it's a Future

       每一次对get的调用都会发生阻塞直到结果可获得为止。当然,线程时并行运行的,因此,很可能在大致相同的时刻所有的结果都可获得。

实例如下:

package com.thread.callable;import java.io.File;import java.util.Scanner;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;public class FutureTest {public static void main(String[] args) {Scanner in = new Scanner(System.in);System.out.println("请输入目录:");String directory = in.nextLine();System.out.println("请输入关键字:");String keyword = in.nextLine();MatchCounter counter = new MatchCounter(new File(directory), keyword);FutureTask<Integer> task = new FutureTask<>(counter);Thread t = new Thread(task);t.start();try {System.out.println(task.get()+" matching files.");} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}in.close();}}
package com.thread.callable;import java.io.File;import java.io.FileNotFoundException;import java.util.ArrayList;import java.util.List;import java.util.Scanner;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.Future;import java.util.concurrent.FutureTask;public 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() {count = 0;try {File[] files = directory.listFiles();List<Future<Integer>> results = new ArrayList<>();for (File file : files) {if (file.isDirectory()) {MatchCounter counter = new MatchCounter(file, keyword);FutureTask<Integer> task = new FutureTask<>(counter);results.add(task);Thread t = new Thread(task);t.start();} else {if (search(file))count++;}}for (Future<Integer> result : results) {try {count += result.get();} catch (ExecutionException e) {e.printStackTrace();}}} catch (InterruptedException e) {}return count;}public boolean search(File file) {try (Scanner in = new Scanner(file)) {boolean found = false;while (!found && in.hasNext()) {String line = in.nextLine();if (line.contains(keyword))return found = true;}return found;} catch (FileNotFoundException e) {e.printStackTrace();return false;}}}

常用方法:  V call()  运行一个将产生结果的任务

                   V get() 

                   V get(long time,TimeUnit unit)  获取结果,如果没有结果可用,则阻塞直到真正得到结果超过指定时间为止。如果不成功,第二个方法会抛出TimeoutException异常。

                   FutureTask(Callable<V> task) 

                   FutureTask(Runnable task,V result) 构造一个既是Funture<V>又是Runnable的对象。

0 0
原创粉丝点击