本文主要是介绍Callable及Future,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1.Runnable
Runnable是个接口,使用很简单:
1. 实现该接口并重写run方法
2. 利用该类的对象创建线程
3. 线程启动时就会自动调用该对象的run方法
通常在开发中结合ExecutorService使用,将任务的提交与任务的执行解耦开,同时也能更好地利用Executor提供的各种特性
ExecutorService executor = Executors.newCachedThreadPool();executor.submit(new Runnable() { public void run() {//TODO }}); executor.shutdown();
相对于继承Thread来创建线程方式,使用Runnable可以让你的实现类同时实现多个接口,而相对于Callable及Future,Runnable方法并不返回任务执行结果且不能抛出异常
2.Callable
与Runnable不同的是,Callable是个泛型参数化接口,并能返回线程的执行结果,且能在无法正常计算时抛出异常
public interface Callable<V> {V call() throws Exception; }
1. Callable并不像Runnable那样通过Thread的start方法就能启动实现类的run方法,所以它通常利用ExecutorService的submit方法去启动call方法自执行任务,而ExecutorService的submit又返回一个Future类型的结果,因此Callable通常也与Future一起使用
ExecutorService pool = Executors.newCachedThreadPool();Future<String> future = pool.submit(new Callable{public void call(){//TODO }});
或者利用FutureTask封装Callable再由Thread去启动(少用)
FutureTask<String> task = new FutureTask(new Callable{public void call(){//TODO }});Thead thread = new Thread(task);thread.start();
2. 通过Executors.callbale(Runnable task,T result)可以执行Runnable并返回"结果",但是这个结果并不是Runnable的执行结果(Runnable的run方法是void类型),而是执行者预定义的结果,这点可以从其实现原理RunnableAdpter源码看出
public static <T> Callable<T> callable(Runnable task, T result) {if (task == null)throw new NullPointerException();return new RunnableAdapter<T>(task, result);//通过RunnableAdapter实现 }static final class RunnableAdapter<T> implements Callable<T> {final Runnable task;final T result;RunnableAdapter(Runnable task, T result) {this.task = task;this.result = result;}public T call() {task.run();return result; //将传入的结果的直接返回}}
Runnable与Callable不同点:
1. Runnable不返回任务执行结果,Callable可返回任务执行结果
2. Callable在任务无法计算结果时抛出异常,而Runnable不能
3. Runnable任务可直接由Thread的start方法或ExecutorService的submit方法去执行
3.Future
Future保存异步计算的结果,可以在我们执行任务时去做其他工作,并提供了以下几个方法
* cancel(boolean mayInterruptIfRunning):试图取消执行的任务,参数为true时直接中断正在执行的任务,否则直到当前任务执行完成,成功取消后返回true,否则返回false
* isCancel():判断任务是否在正常执行完前被取消的,如果是则返回true
* isDone():判断任务是否已完成
* get():等待计算结果的返回,如果计算被取消了则抛出
* get(long timeout,TimeUtil unit):设定计算结果的返回时间,如果在规定时间内没有返回计算结果则抛出TimeOutException
使用Future的好处:
1. 获取任务的结果,判断任务是否完成,中断任务
1. Future的get方法很好的替代的了Thread.join或Thread,join(long millis)
2. Future的get方法可以判断程序代码(任务)的执行是否超时,如:
try{future.get(60,TimeUtil.SECOND);}catch(TimeoutException timeout){log4j.log("任务越野,将被取消!!");future.cancel();}
4.FutureTask
FutureTask实现了RunnableFuture接口,提供了即可以使用Runnable来执行任务,又可以使用Future执行任务并取得结果的构造器,所以可以利用FutureTask去封装Runnable或Callable对象,之后再submit任务
FutureTask(Callable<V> callable) FutureTask(Runnable runnable, V result)
5.应用
查找包含某关键字的文件个数:每个文件启动一个线程去查找关键字
public class FileSearchTask {public static void main(String[] args) throws ExecutionException, InterruptedException {String path = args[0];String keyword = args[1];int c = 0;File[] files = new File(path).listFiles();ArrayList<Future<Integer>> rs = new ArrayList<>();for(File file: files){ //每个文件启动一个task去查找MatchCount count = new MatchCount();count.file = file;count.keyword = keyword;FutureTask<Integer> task = new FutureTask(count);rs.add(task); //将任务返回的结果添加到集合中Thread thread = new Thread(task);thread.start();}for(Future<Integer> f: rs){c += f.get(); //迭代返回结果并累加 }System.out.println("包含关键字的总文件数为:" + c);} }class MatchCount implements Callable<Integer>{public File file;public String keyword;private Integer count = 0;public Integer call() throws Exception { //call封装线程所需做的任务if(search(file))count ++;return count;}public boolean search(File file){boolean founded = false;try(Scanner scanner = new Scanner(new FileInputStream(file))){while(!founded && scanner.hasNextLine()){if (scanner.nextLine().contains(keyword))founded = true;}} catch (FileNotFoundException e) {e.printStackTrace();}return founded;} }
这篇关于Callable及Future的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!