Java多线程技术研究(四)-Callable,Future/FutureTask,及Future设计模式
来源:互联网 发布:房地产动画制作软件 编辑:程序博客网 时间:2024/05/21 21:44
本篇博客Java多线程中另一块重要的内容:Callable,Future,FutureTask,及Future设计模式的模拟实现。
考虑这样一种场景: 网上购物,提交订单后,在收货的这段时间里无需一直在家里等候,可以先干别的事情。类推到程序设计中时,当提交请求时,期望得到答复时,如果这个答复可能很慢。传统的做法一直等待直到收到应答,可能才会去做后续的事情。在Java中提供Callable和Future机制实现了异步调用,即主线程为得到某个答复,创建一个子线程等待该答复,然后主线程在这个过程中干其他事情,办完其它事情后再去获得答复。我们把这种设计称为Future设计模式。
1、Callable和Runnable
在Java多线程技术研究(一) 中,Callable和Runnable一样,都是实现多线程的一种方法,但是Runnable不会返回结果,并且无法抛出带返回结果的异常,而Callable功能更加强大一些,线程执行结束后可以返回结果。这个结果可以通过Future或FutureTask拿到该线程的返回值。
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;}
Runnable接口run()方法返回值为void型,显然不可获得其执行结果
publicinterface Runnable { /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. * <p> * The general contract of the method <code>run</code> is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run();}
2、Callable和Future获取线程执行结果
Future接口中定义有如下方法:
1)cancel()
boolean cancel(boolean mayInterruptIfRunning);
取消任务的执行,mayInterruptRunning参数表示是否中断执行中的线程。
2)isCancelled()
boolean isCancelled();
任务是否已取消,如果在正常完成前已取消返回true。
3)isDone()
boolean isDone();
任务是否已完成,不管该任务是正常停止,异常导致,主动终止,均返回true。
4)get()
V get() throws InterruptedException, ExecutionException;
获取异步执行的结果,如果任务没有执行结束,此方法会阻塞直到任务完成。
5) get(long timeout, TimeUnit unit)
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
其中timeout为超时时间,unit为时间单位,如果在阻塞timeout时间,仍没有获得返回结果,get()方法会抛出TimeoutException异常。
下面来看利用Callable和Future获取线程执行结果
package com.wygu.thread.study;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;import java.util.concurrent.FutureTask;public class MultiThreadCallable { public static void main(String []argv){ TaskCallable tCallable = new TaskCallable(); ExecutorService executorService = Executors.newSingleThreadExecutor(); //将任务提交到线程池中 Future<Integer> future =executorService.submit(tCallable); //主线程可以进行其他事情 try { Integer result = future.get(); System.out.println("子线程返回结果为:"+result); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }}class TaskCallable implements Callable<Integer>{ @Override public Integer call(){ int num=10; try { Thread.sleep(3000); num+=10; } catch (InterruptedException e) { e.printStackTrace(); } return num; }}
子线程返回结果为:20
3、Callable和FutureTask
首先看一下类FutureTask的实现:
public class FutureTask<V> implements RunnableFuture<V>
FutureTask实现了接口RunnableFuture,而对于RunnableFuture的实现:
public interface RunnableFuture<V> extends Runnable, Future<V>
RunnableFuture不仅实现了Future中的方法,还实现了Runnable中run方法。
因而FutureTask不仅可以直接提交给Executor执行,还可以调用线程直接执行FutureTask中实现的run()方法.
通过FutureTask的下述两种构造方法,利用FutureTask可以获得Runnable的中执行结果。
public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable } public FutureTask(Runnable runnable, V result) { this.callable = Executors.callable(runnable, result); this.state = NEW; // ensure visibility of callable }
下面来看利用Callable和FutureTask获取线程执行结果
public class MultiThreadCallable { public static void main(String []argv){ TaskCallable tCallable = new TaskCallable(); FutureTask<Integer> futureTask = new FutureTask<Integer>(tCallable); new Thread(futureTask,"带返回值的线程").start(); //主线程可以进行其他事情 try { Integer result = futureTask.get(); System.out.println("子线程返回结果为:"+result); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }}class TaskCallable implements Callable<Integer>{ @Override public Integer call(){ int num=10; try { Thread.sleep(3000); num+=10; } catch (InterruptedException e) { e.printStackTrace(); } return num; }}
程序执行结果:
子线程返回结果为:20
4、Future设计模式的模拟实现
在前面的场景中:网上挑好物品后,提交表单会获得一个订单,然后就可以等待收货,在收货的这段时间里无需一直在家里等候,可以先干别的事情。
图片来源于:http://blog.csdn.net/ghuil/article/details/41048017
在传统多线程模式,采用的是同步调用方式,Client发出call请求后,会一直等待服务端给予真实的应答数据,只有当Client等待到应答后,才能进行其它事情。而在Future设计模式调用中,Client发出call请求后,Server端会立即给予Client端一个应答,此时的应答数据可以说是一个假数据(不是真实的结果),Client端收到Server端的应答后,就去处理其它事情了,而Server端内部可以慢慢的生产数据,完成后把放置在对象中,等待Client端获取。
下面给出Future模式的程序实现
1)FutureClient的实现
FutureClient主要功能包括:获得假数据FutureData,获得真实数据RealData
package com.wygu.futurePattern;public class FutureClient<T> { private T requestData = null; public FutureClient(T requestdata){ this.requestData = requestdata; } //创建方法,获得真实的数据 public FutureData<T> callForBack(){ final FutureData<T> fData = new FutureData<T>(); new Thread(new Runnable() { @Override public void run() { RealData<T> realData = new RealData<T>(requestData); fData.setRealData(realData); } }).start(); return fData; }}
2)Data的实现
接口Data中,定义一个获得数据的方法getResult(),在FutureData,RealData均重新实现该接口。其中FutureData可以说是对RealData的代理,它会封装RealData的getResult()方法。
Data接口定义
package com.wygu.futurePattern;public interface Data<T> { public T getResult() throws InterruptedException;}
FutureData的实现
package com.wygu.futurePattern;public class FutureData<T> implements Data<T>{ private RealData<T> realData = null; private volatile boolean isReady = false; public synchronized void setRealData(RealData<T> realData) { //判断真实数据是否已完成 if(isReady){ return; } this.realData = realData; //数据已生产好 this.isReady = true; //唤醒等待的线程 notifyAll(); } @Override public synchronized T getResult() throws InterruptedException { if(!isReady){ wait();//阻塞调用该方法的线程,产生真实的数据 } return realData.getResult(); }}
RealData的实现
package com.wygu.futurePattern;@SuppressWarnings("rawtypes")public class RealData<T> implements Data{ private T realData = null; public RealData(T realData) { //使用sleep模拟生产真实数据很慢 try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } this.realData = realData; } @Override public T getResult() throws InterruptedException{ //获取生产的真实数据 return realData; }}
3)测试运行
package com.wygu.futurePattern;public class Main { public static void main(String[] args) { long start = System.currentTimeMillis(); FutureClient<String> futureClient = new FutureClient<String>("Hi,Future Pattern"); //主线程创建Client实例,去请求真实数据 FutureData<String> futureData = futureClient.callForBack(); //让主线程沉睡一段时间,在去获得真实数据 try { Thread.sleep(9000); } catch (InterruptedException e) { e.printStackTrace(); } try { System.out.println("Client 获取真实数据:"+futureData.getResult()+",共耗时:"+(System.currentTimeMillis()-start)+"毫秒"); } catch (InterruptedException e) { e.printStackTrace(); } }}
运行结果为:Client 获取真实数据:Hi,Future Pattern,共耗时:9997毫秒
修改主线程做其他工作时间(沉睡时间)为Thread.sleep(11000),运行结果为:Client 获取真实数据:Hi,Future Pattern,共耗时:10994毫秒。假设主线程的处理其它事物的时间为t1,Server端产生真实数据的时间为t2,则主线程运行结束的时间为max(t1,t2).
- Java多线程技术研究(四)-Callable,Future/FutureTask,及Future设计模式
- Java多线程 Callable Future FutureTask
- 【Java多线程】-Callable,Future,FutureTask
- 多线程--callable、Future、FutureTask
- Java多线程之 Callable、Future和FutureTask
- Java多线程之Callable、Future和FutureTask
- Java多线程:Callable、Future和FutureTask
- Java多线程:Callable、Future和FutureTask
- Java多线程之Callable、Future和FutureTask
- Java多线程编程:Callable、Future和FutureTask浅析(多线程编程之四)
- Java多线程编程:Callable、Future和FutureTask浅析(多线程编程之四)
- Java多线程(二)——Callable、Future和FutureTask
- 多线程之 Callable Future FutureTask
- java 多线程( Future Callable)
- Java多线程:Callable、ExecutorService、CountDownLatch、Future和FutureTask
- JAVA---多线程之Callable与Future,FutureTask,及其简单应用
- java多线程Runnable、Callable、Executor、Future、FutureTask关系解读
- java多线程编程之Callable、Future和FutureTask。
- 安卓开发——让系统可以调用自己写的视频播放器
- 12.函数
- Java基础学习笔记 第二部分 part 3
- Oracle Minus关键字
- 0021_Merge Two Sorted Lists
- Java多线程技术研究(四)-Callable,Future/FutureTask,及Future设计模式
- 快速排序
- python 文本情感分类
- tensorflow1.0安装
- Linux下redis的安装及部署
- Java内存管理机制
- Loadrunner模拟JSON接口请求进行测试
- 计算机 女毕业 四年开始抓 起JAVA,加油,工科女,你是好样的!
- 手机身份证识别OCR识别