线程技术 ☞ Future模式
线程技术可以让我们的程序同时做多件事情,线程的工作模式有很多,常见的一种模式就是处理网站的并发,今天我来说说线程另一种很常见的模式,这个模式和前端里的ajax类似:浏览器一个主线程执行javascript,页面渲染等操作,当我们使用ajax向服务端发起请求,由于这个过程很慢,ajax的异步模式可以让我们无需一直等待服务端的响应,而在这个等待结果时间里做其他的事情,这个模式在线程技术力称之为Future模式。
Future模式和我前面文章里说到的html5技术里的worker技术差不多,当我们一个程序执行流里某个操作特别耗时,我们可以另起一个线程专门执行这个繁琐耗时的任务,主线程则可以做其他的事情,下面是我自己找到的一个实现原生Future模式的代码,它主要参入者如下:
TestMain.java:测试程序入口,主要是调用Client类,向Client发送请求;
Client.java:返回Data对象,立即返回FutureData,并开启ClientThread线程装配RealData;
Data.java:返回数据接口;
FutureData.java:Future数据,构造快,但是是一个虚拟的数据,需要装配RealData;
RealData.java:真实数据,其构造是比较慢的。
详细代码如下:
Data接口:
- package cn.com.xSharp.futurePattern.simple;
- /**
- * 数据接口
- */
- public interface Data {
- public String getData();
- }
RealData代码:
- package cn.com.xSharp.futurePattern.simple;
- /**
- * RealData是最终使用的数据,它构造很慢,因此用sleep来模拟
- */
- public class RealData implements Data {
- protected final String result;
- public RealData(String param) {
- StringBuffer sb = new StringBuffer();
- for (int i = ;i < ;i++){
- sb.append(param);
- try {
- Thread.sleep();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- result = sb.toString();
- }
- @Override
- public String getData() {
- return result;
- }
- }
FutureData代码:
- package cn.com.xSharp.futurePattern.simple;
- public class FutureData implements Data {
- protected RealData realData = null;// FutureData对RealData的包装
- protected boolean isReady = false;
- public synchronized void setRealData(RealData realData){
- if (isReady){
- return;
- }
- this.realData = realData;
- isReady = true;
- notifyAll();
- }
- @Override
- public synchronized String getData() {
- while (!isReady){
- try {
- wait();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- return realData.result;
- }
- }
Client代码:
- package cn.com.xSharp.futurePattern.simple;
- public class Client {
- public Data request(final String qryStr){
- final FutureData futureData = new FutureData();
- new Thread(){
- public void run(){
- RealData realData = new RealData(qryStr);
- futureData.setRealData(realData);
- }
- }.start();
- return futureData;
- }
- }
TestMain代码:
- package cn.com.xSharp.futurePattern.simple;
- public class TestMain {
- public static void main(String[] args) {
- Client client = new Client();
- Data data = client.request("xtq");
- System.out.println("请求完毕!");
- try {
- for (int i = ;i < ;i++){
- Thread.sleep();
- System.out.println("可以做做其他的事情哦....");
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("数据==:" + data.getData());
- }
- }
执行结果:
- 1 请求完毕!
- 2 可以做做其他的事情哦....
- 3 可以做做其他的事情哦....
- 4 可以做做其他的事情哦....
- 5 可以做做其他的事情哦....
- 6 可以做做其他的事情哦....
- 7 可以做做其他的事情哦....
- 8 可以做做其他的事情哦....
- 9 可以做做其他的事情哦....
- 10 可以做做其他的事情哦....
- 11 可以做做其他的事情哦....
- 12 可以做做其他的事情哦....
- 13 可以做做其他的事情哦....
- 14 数据==:xtqxtqxtqxtqxtqxtqxtqxtqxtqxtq
JDK里在1.5之后提供了专门Future模式的实现,这里我使用FutureTask来实现Future模式。
FutureTask在JDK文档里的解释:
可取消的异步计算。利用开始和取消计算的方法、查询计算是否完成的方法和获取计算结果的方法,此类提供了对 Future 的基本实现。仅在计算完成时才能获取结果;如果计算尚未完成,则阻塞 get 方法。一旦计算完成,就不能再重新开始或取消计算。 可使用 FutureTask 包装 Callable 或 Runnable 对象。因为 FutureTask 实现了 Runnable,所以可将 FutureTask 提交给 Executor 执行。 除了作为一个独立的类外,此类还提供了 protected 功能,这在创建自定义任务类时可能很有用。
下面是它的两个构造函数:
FutureTask(Callable<V> callable) 创建一个 FutureTask,一旦运行就执行给定的 Callable。 FutureTask(Runnable runnable, V result) 创建一个 FutureTask,一旦运行就执行给定的 Runnable,并安排成功完成时 get 返回给定的结果 。 |
这里我首先使用第二个构造函数Runnable实现Future模式,代码如下:
- package cn.com.futuretest;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.FutureTask;
- public class FutureRunnable implements Runnable{
- private Result result; // 操作的数据,模拟一个计算需要很长时间的数据
- /* 初始化数据 */
- public FutureRunnable(Result result) {
- this.result = result;
- }
- @Override
- public void run() {
- try {
- for (int i = ;i < ;i++){
- Thread.sleep();// 每隔100毫秒操作一次数据,模拟数据被长时间计算的场景
- result.setData(result.getData() + ":" + "futureRunnable" + i);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args) {
- Result r = new Result("xSharp");// 构造测试数据
- FutureRunnable futureCallable = new FutureRunnable(r);// 初始化runnable
- FutureTask<Result> task = new FutureTask<Result>(futureCallable, r);
- // 构造固定大小为一个线程的线程池
- ExecutorService executorService = Executors.newFixedThreadPool();
- // 执行线程
- executorService.execute(task);
- System.out.println("执行完毕!");
- try {
- for (int i = ;i < ;i++){
- Thread.sleep();
- System.out.println("数据还在计算中等待中,你可以做别的事情" + i);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- try {
- System.out.println("打印结果是:" + task.get().getData());
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }finally{
- System.exit();
- }
- }
- }
执行结果:
- 执行完毕!
- 数据还在计算中等待中,你可以做别的事情0
- 数据还在计算中等待中,你可以做别的事情1
- 数据还在计算中等待中,你可以做别的事情2
- 数据还在计算中等待中,你可以做别的事情3
- 数据还在计算中等待中,你可以做别的事情4
- 数据还在计算中等待中,你可以做别的事情5
- 数据还在计算中等待中,你可以做别的事情6
- 数据还在计算中等待中,你可以做别的事情7
- 数据还在计算中等待中,你可以做别的事情8
- 数据还在计算中等待中,你可以做别的事情9
- 数据还在计算中等待中,你可以做别的事情10
- 数据还在计算中等待中,你可以做别的事情11
- 数据还在计算中等待中,你可以做别的事情12
- 数据还在计算中等待中,你可以做别的事情13
- 数据还在计算中等待中,你可以做别的事情14
- 打印结果是:xSharp:futureRunnable0:futureRunnable1:futureRunnable2:futureRunnable3:futureRunnable4:futureRunnable5:futureRunnable6:futureRunnable7:futureRunnable8:futureRunnable9
接下来我使用Callable<V> 接口实现FutureTask,代码如下:
- package cn.com.futuretest;
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.FutureTask;
- public class FutureCallable implements Callable<Result>{
- private Result result; // 操作的数据,模拟一个计算需要很长时间的数据
- /* 初始化数据 */
- public FutureCallable(Result result) {
- this.result = result;
- }
- @Override
- public Result call() throws Exception {
- try {
- for (int i = ;i < ;i++){
- Thread.sleep();// 每隔100毫秒操作一次数据,模拟数据被长时间计算的场景
- result.setData(result.getData() + ":" + "futureCallable" + i);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return result;
- }
- public static void main(String[] args) {
- long start = System.currentTimeMillis();
- Result r = new Result("xSharp");// 构造测试数据
- FutureCallable callable = new FutureCallable(r);
- FutureTask<Result> task = new FutureTask<Result>(callable);
- // 构造固定大小为一个线程的线程池
- ExecutorService executorService = Executors.newFixedThreadPool();
- // 执行线程
- executorService.execute(task);
- System.out.println("执行完毕!");
- long curr01 = System.currentTimeMillis();
- System.out.println("任务提交后的耗时:" + (curr01 - start) + "毫秒");
- try {
- for (int i = ;i < ;i++){
- Thread.sleep();
- System.out.println("数据还在计算中等待中,你可以做别的事情" + i);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- try {
- System.out.println("打印结果是:" + task.get().getData());
- long end = System.currentTimeMillis();
- System.out.println("总耗时:" + (end - start) + "毫秒");
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }finally{
- System.exit();
- }
- }
- }
执行结果如下:
- 执行完毕!
- 任务提交后的耗时:6毫秒
- 数据还在计算中等待中,你可以做别的事情0
- 数据还在计算中等待中,你可以做别的事情1
- 数据还在计算中等待中,你可以做别的事情2
- 数据还在计算中等待中,你可以做别的事情3
- 数据还在计算中等待中,你可以做别的事情4
- 数据还在计算中等待中,你可以做别的事情5
- 打印结果是:xSharp:futureCallable0:futureCallable1:futureCallable2:futureCallable3:futureCallable4:futureCallable5:futureCallable6:futureCallable7:futureCallable8:futureCallable9
- 总耗时:1010毫秒
这里我对代码做了一些调整,一个是加上了执行时间的统计,一个是我将干其他事情的程序执行时间变短,小于了线程本身执行的时间,这么做的目的是想和下面的程序对比,下面的代码当我执行线程后没有做其他的操作,而是直接获取线程执行的结果,具体代码如下:
- package cn.com.futuretest;
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.FutureTask;
- public class NioFutureCallable implements Callable<Result> {
- private Result result; // 操作的数据,模拟一个计算需要很长时间的数据
- /* 初始化数据 */
- public NioFutureCallable(Result result) {
- this.result = result;
- }
- @Override
- public Result call() throws Exception {
- try {
- for (int i = ;i < ;i++){
- Thread.sleep();// 每隔100毫秒操作一次数据,模拟数据被长时间计算的场景
- result.setData(result.getData() + ":" + "NioFutureCallable" + i);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return result;
- }
- public static void main(String[] args) {
- long start = System.currentTimeMillis();
- Result r = new Result("xSharp");// 构造测试数据
- NioFutureCallable callable = new NioFutureCallable(r);
- FutureTask<Result> task = new FutureTask<Result>(callable);
- // 构造固定大小为一个线程的线程池
- ExecutorService executorService = Executors.newFixedThreadPool();
- // 执行线程
- executorService.execute(task);
- System.out.println("执行完毕!");
- long curr01 = System.currentTimeMillis();
- System.out.println("任务提交后的耗时:" + (curr01 - start) + "毫秒");
- /* 第一次获取返回数据 */
- try {
- System.out.println("第一次打印结果是:" + task.get().getData());
- long curr02 = System.currentTimeMillis();
- System.out.println("第一次获取结果耗时:" + (curr02 - start) + "毫秒");
- } catch (InterruptedException e1) {
- e1.printStackTrace();
- } catch (ExecutionException e1) {
- e1.printStackTrace();
- }
- try {
- for (int i = ;i < ;i++){
- Thread.sleep();
- System.out.println("数据还在计算中等待中,你可以做别的事情" + i);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- try {
- System.out.println("第二次打印结果是:" + task.get().getData());
- long end = System.currentTimeMillis();
- System.out.println("总耗时:" + (end - start) + "毫秒");
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }finally{
- System.exit();
- }
- }
- }
执行结果如下:
- 1 执行完毕!
- 2 任务提交后的耗时:7毫秒
- 3 第一次打印结果是:xSharp:NioFutureCallable0:NioFutureCallable1:NioFutureCallable2:NioFutureCallable3:NioFutureCallable4:NioFutureCallable5:NioFutureCallable6:NioFutureCallable7:NioFutureCallable8:NioFutureCallable9
- 4 第一次获取结果耗时:1009毫秒
- 5 数据还在计算中等待中,你可以做别的事情0
- 6 数据还在计算中等待中,你可以做别的事情1
- 7 数据还在计算中等待中,你可以做别的事情2
- 8 数据还在计算中等待中,你可以做别的事情3
- 9 数据还在计算中等待中,你可以做别的事情4
- 10 数据还在计算中等待中,你可以做别的事情5
- 11 数据还在计算中等待中,你可以做别的事情6
- 12 数据还在计算中等待中,你可以做别的事情7
- 13 数据还在计算中等待中,你可以做别的事情8
- 14 数据还在计算中等待中,你可以做别的事情9
- 15 第二次打印结果是:xSharp:NioFutureCallable0:NioFutureCallable1:NioFutureCallable2:NioFutureCallable3:NioFutureCallable4:NioFutureCallable5:NioFutureCallable6:NioFutureCallable7:NioFutureCallable8:NioFutureCallable9
- 16 总耗时:2012毫秒
我们看到当我们直接获取结果时候,整个主线程都被阻塞了,直到结果返回后才会执行下面的后续操作,这也就是说如果计算还没结束,我们就想获取结果这样整个执行流程都将被阻塞,这点在我们合理使用Future模式时候很重要。
除了使用FutureTask实现Future模式,我们还可以使用ExecutorService的submit方法直接返回Future对象,Future就和我前面设计的原生Future类似,当我们开始调用时候返回的是一个虚拟结果,其实实际的计算还没有结束,只有等待吗一会儿后结果才会真正的返回,代码如下:
- package cn.com.futuretest;
- 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;
- public class RetFutureCallable implements Callable<Result>{
- private Result result; // 操作的数据,模拟一个计算需要很长时间的数据
- public RetFutureCallable() {
- result = new Result("xSharp");
- }
- @Override
- public Result call() throws Exception {
- try {
- for (int i = ;i < ;i++){
- Thread.sleep();// 每隔100毫秒操作一次数据,模拟数据被长时间计算的场景
- result.setData(result.getData() + ":" + "RetFutureCallable" + i);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return result;
- }
- public static void main(String[] args) {
- long start = System.currentTimeMillis();
- RetFutureCallable callable = new RetFutureCallable();
- // 构造固定大小为一个线程的线程池
- ExecutorService executorService = Executors.newFixedThreadPool();
- // 执行线程
- Future<Result> r = executorService.submit(callable);
- System.out.println("执行完毕!");
- long curr01 = System.currentTimeMillis();
- System.out.println("任务提交后的耗时:" + (curr01 - start) + "毫秒");
- try {
- for (int i = ;i < ;i++){
- Thread.sleep();
- System.out.println("数据还在计算中等待中,你可以做别的事情" + i);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- try {
- System.out.println("打印结果是:" + r.get().getData());
- long end = System.currentTimeMillis();
- System.out.println("总耗时:" + (end - start) + "毫秒");
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }finally{
- System.exit();
- }
- }
- }
执行结果如下:
- 1 执行完毕!
- 2 任务提交后的耗时:5毫秒
- 3 数据还在计算中等待中,你可以做别的事情0
- 4 数据还在计算中等待中,你可以做别的事情1
- 5 数据还在计算中等待中,你可以做别的事情2
- 6 数据还在计算中等待中,你可以做别的事情3
- 7 数据还在计算中等待中,你可以做别的事情4
- 8 数据还在计算中等待中,你可以做别的事情5
- 9 打印结果是:xSharp:RetFutureCallable0:RetFutureCallable1:RetFutureCallable2:RetFutureCallable3:RetFutureCallable4:RetFutureCallable5:RetFutureCallable6:RetFutureCallable7:RetFutureCallable8:RetFutureCallable9
- 10 总耗时:1006毫秒
转自:http://www.cnblogs.com/sharpxiajun/p/5608663.html
线程技术 ☞ Future模式的更多相关文章
- Java中的Future模式原理自定义实现
摘要:Future模式类似于js中的ajax等,是一个异步获取数据的机制,这里我把自己的一些形象理解通过代码实现了一下.该机制可以形象的理解为:调用获取数据的方法,首先获得一个没有装数据的空箱子(这个 ...
- 线程笔记:Future模式
线程技术可以让我们的程序同时做多件事情,线程的工作模式有很多,常见的一种模式就是处理网站的并发,今天我来说说线程另一种很常见的模式,这个模式和前端里的ajax类似:浏览器一个主线程执行javascri ...
- 深入理解[Future模式]原理与技术
1.Future模式 Future模式和多线程技术密切相关,可以说是利用多线程技术优化程序的一个实例. 在程序设计中,当某一段程序提交了一个请求,期望得到一个答复.但非常不幸的是,服务程序对这个请求的 ...
- Java线程池(Callable+Future模式)
转: Java线程池(Callable+Future模式) Java线程池(Callable+Future模式) Java通过Executors提供四种线程池 1)newCachedThreadPoo ...
- java future模式 所线程实现异步调用(转载
java future模式 所线程实现异步调用(转载) 在多线程交互的中2,经常有一个线程需要得到另个一线程的计算结果,我们常用的是Future异步模式来加以解决.Future顾名思意,有点像期货市场 ...
- 架构师养成记--9.future模式讲解
什么是future模式呢?解释这个概念之前我们先来了解一个场景吧,财务系统的结账功能,这个功能可能是每个月用一次,在这一个月中相关的数据量已经积累得非常大,这一个功能需要调用好几个存储过程来完成.假如 ...
- Future模式
Future模式简介 Future模式有点类似于网上购物,在你购买商品,订单生效之后,你可以去做自己的事情,等待商家通过快递给你送货上门.Future模式就是,当某一程序提交请求,期望得到一个答复.但 ...
- 闲谈Future模式-订蛋糕
一. Future模式简介 Future有道翻译:n. 未来:前途:期货:将来时.我觉得用期货来解释比较合适.举个实际生活中例子来说吧,今天我女朋友过生日,我去蛋糕店准备给女朋友定个大蛋糕,超级大的那 ...
- java Future 模式
考慮這樣一個情況,使用者可能快速翻頁瀏覽文件中,而圖片檔案很大,如此在瀏覽到有圖片的頁數時,就會導致圖片的載入,因而造成使用者瀏覽文件時會有停頓 的現象,所以我們希望在文件開啟之後,仍有一個背景作業持 ...
随机推荐
- DevOps - Development And Operations
简介: 研发运维一体化 相关资料: 关于DevOps你必须知道的11件事 我眼中的DevOps DevOps 门户 docker for dotnet系列 docker4dotnet #1 前世今生 ...
- java design
http://www.austintek.com/mvc/ http://msdn.microsoft.com/zh-cn/magazine/cc163419.aspx http://www.croc ...
- K Smallest Sums
uva11997:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_prob ...
- hdu 5147 Sequence II
http://acm.hdu.edu.cn/showproblem.php?pid=5147 题意:问有多少个这样的四元组(a,b,c,d),满足条件是 1<=a<b<c<d; ...
- Android 开机自启动
首先实现开机自启动: 第一步创建一个广播接收者,如MyBootBroadcastReceiver.java package com.example; import android.content.Br ...
- 数据结构算法集---C++语言实现
//数据结构算法集---C++语言实现 //各种类都使用模版设计,可以对各种数据类型操作(整形,字符,浮点) /////////////////////////// // // // 堆栈数据结构 s ...
- SRM 397(1-250pt)
题意:对于一个长度n的数列(由1-n组成,n <= 8),每次操作可以reverse k个连续的数.问最少多少次操作可以将该数列转化成递增的数列. 解法:就是一个BFS.只是由于最开始学习BFS ...
- redmine安装插件流程
1.redmine用一键安装即可2.进入C:\Bitnami\redmine-3.1.1-1\,执行use_redmine.exe,进入dos系统 不能用cmd进入.3.把文件拷贝到C:\Bitnam ...
- Vs 2008 对 OpenMP 的 支持 以及 OpenMP的环境变量及库函数
Visual C++® 2008对OpenMP的支持 VC++2008根据项目属性配置的指示进行 /openmp编译器切换,当配置了OpenMP支持后,编译器会提供_OPENMP定义,可以使用#ifd ...
- Android 免费短信获取国家列表和国家代码
StringBuffer str = new StringBuffer(); for (Map.Entry<Character, ArrayList<String[]>> en ...