线程技术可以让我们的程序同时做多件事情,线程的工作模式有很多,常见的一种模式就是处理网站的并发,今天我来说说线程另一种很常见的模式,这个模式和前端里的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接口:

  1. package cn.com.xSharp.futurePattern.simple;
  2.  
  3. /**
  4. * 数据接口
  5. */
  6. public interface Data {
  7. public String getData();
  8. }

RealData代码:

  1. package cn.com.xSharp.futurePattern.simple;
  2.  
  3. /**
  4. * RealData是最终使用的数据,它构造很慢,因此用sleep来模拟
  5. */
  6. public class RealData implements Data {
  7.  
  8. protected final String result;
  9.  
  10. public RealData(String param) {
  11. StringBuffer sb = new StringBuffer();
  12. for (int i = ;i < ;i++){
  13. sb.append(param);
  14. try {
  15. Thread.sleep();
  16. } catch (Exception e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. result = sb.toString();
  21. }
  22.  
  23. @Override
  24. public String getData() {
  25. return result;
  26. }
  27. }

FutureData代码:

  1. package cn.com.xSharp.futurePattern.simple;
  2.  
  3. public class FutureData implements Data {
  4.  
  5. protected RealData realData = null;// FutureData对RealData的包装
  6. protected boolean isReady = false;
  7.  
  8. public synchronized void setRealData(RealData realData){
  9. if (isReady){
  10. return;
  11. }
  12. this.realData = realData;
  13. isReady = true;
  14. notifyAll();
  15. }
  16.  
  17. @Override
  18. public synchronized String getData() {
  19. while (!isReady){
  20. try {
  21. wait();
  22. } catch (Exception e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. return realData.result;
  27. }
  28.  
  29. }

Client代码:

  1. package cn.com.xSharp.futurePattern.simple;
  2.  
  3. public class Client {
  4.  
  5. public Data request(final String qryStr){
  6. final FutureData futureData = new FutureData();
  7. new Thread(){
  8. public void run(){
  9. RealData realData = new RealData(qryStr);
  10. futureData.setRealData(realData);
  11. }
  12. }.start();
  13. return futureData;
  14. }
  15. }

TestMain代码:

  1. package cn.com.xSharp.futurePattern.simple;
  2.  
  3. public class TestMain {
  4.  
  5. public static void main(String[] args) {
  6. Client client = new Client();
  7. Data data = client.request("xtq");
  8. System.out.println("请求完毕!");
  9.  
  10. try {
  11. for (int i = ;i < ;i++){
  12. Thread.sleep();
  13. System.out.println("可以做做其他的事情哦....");
  14. }
  15.  
  16. } catch (InterruptedException e) {
  17. e.printStackTrace();
  18. }
  19.  
  20. System.out.println("数据==:" + data.getData());
  21. }
  22.  
  23. }

执行结果:

  1. 1 请求完毕!
  2. 2 可以做做其他的事情哦....
  3. 3 可以做做其他的事情哦....
  4. 4 可以做做其他的事情哦....
  5. 5 可以做做其他的事情哦....
  6. 6 可以做做其他的事情哦....
  7. 7 可以做做其他的事情哦....
  8. 8 可以做做其他的事情哦....
  9. 9 可以做做其他的事情哦....
  10. 10 可以做做其他的事情哦....
  11. 11 可以做做其他的事情哦....
  12. 12 可以做做其他的事情哦....
  13. 13 可以做做其他的事情哦....
  14. 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模式,代码如下:

  1. package cn.com.futuretest;
  2.  
  3. import java.util.concurrent.ExecutionException;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. import java.util.concurrent.FutureTask;
  7.  
  8. public class FutureRunnable implements Runnable{
  9. private Result result; // 操作的数据,模拟一个计算需要很长时间的数据
  10.  
  11. /* 初始化数据 */
  12. public FutureRunnable(Result result) {
  13. this.result = result;
  14. }
  15.  
  16. @Override
  17. public void run() {
  18. try {
  19. for (int i = ;i < ;i++){
  20. Thread.sleep();// 每隔100毫秒操作一次数据,模拟数据被长时间计算的场景
  21. result.setData(result.getData() + ":" + "futureRunnable" + i);
  22. }
  23. } catch (InterruptedException e) {
  24. e.printStackTrace();
  25. }
  26. }
  27.  
  28. public static void main(String[] args) {
  29. Result r = new Result("xSharp");// 构造测试数据
  30. FutureRunnable futureCallable = new FutureRunnable(r);// 初始化runnable
  31. FutureTask<Result> task = new FutureTask<Result>(futureCallable, r);
  32. // 构造固定大小为一个线程的线程池
  33. ExecutorService executorService = Executors.newFixedThreadPool();
  34. // 执行线程
  35. executorService.execute(task);
  36. System.out.println("执行完毕!");
  37.  
  38. try {
  39. for (int i = ;i < ;i++){
  40. Thread.sleep();
  41. System.out.println("数据还在计算中等待中,你可以做别的事情" + i);
  42. }
  43. } catch (InterruptedException e) {
  44. e.printStackTrace();
  45. }
  46.  
  47. try {
  48. System.out.println("打印结果是:" + task.get().getData());
  49. } catch (InterruptedException e) {
  50. e.printStackTrace();
  51. } catch (ExecutionException e) {
  52. e.printStackTrace();
  53. }finally{
  54. System.exit();
  55. }
  56. }
  57. }

 执行结果: 

  1. 执行完毕!
  2. 数据还在计算中等待中,你可以做别的事情0
  3. 数据还在计算中等待中,你可以做别的事情1
  4. 数据还在计算中等待中,你可以做别的事情2
  5. 数据还在计算中等待中,你可以做别的事情3
  6. 数据还在计算中等待中,你可以做别的事情4
  7. 数据还在计算中等待中,你可以做别的事情5
  8. 数据还在计算中等待中,你可以做别的事情6
  9. 数据还在计算中等待中,你可以做别的事情7
  10. 数据还在计算中等待中,你可以做别的事情8
  11. 数据还在计算中等待中,你可以做别的事情9
  12. 数据还在计算中等待中,你可以做别的事情10
  13. 数据还在计算中等待中,你可以做别的事情11
  14. 数据还在计算中等待中,你可以做别的事情12
  15. 数据还在计算中等待中,你可以做别的事情13
  16. 数据还在计算中等待中,你可以做别的事情14
  17. 打印结果是:xSharp:futureRunnable0:futureRunnable1:futureRunnable2:futureRunnable3:futureRunnable4:futureRunnable5:futureRunnable6:futureRunnable7:futureRunnable8:futureRunnable9

 接下来我使用Callable<V> 接口实现FutureTask,代码如下:

  1. package cn.com.futuretest;
  2.  
  3. import java.util.concurrent.Callable;
  4. import java.util.concurrent.ExecutionException;
  5. import java.util.concurrent.ExecutorService;
  6. import java.util.concurrent.Executors;
  7. import java.util.concurrent.FutureTask;
  8.  
  9. public class FutureCallable implements Callable<Result>{
  10.  
  11. private Result result; // 操作的数据,模拟一个计算需要很长时间的数据
  12.  
  13. /* 初始化数据 */
  14. public FutureCallable(Result result) {
  15. this.result = result;
  16. }
  17.  
  18. @Override
  19. public Result call() throws Exception {
  20. try {
  21. for (int i = ;i < ;i++){
  22. Thread.sleep();// 每隔100毫秒操作一次数据,模拟数据被长时间计算的场景
  23. result.setData(result.getData() + ":" + "futureCallable" + i);
  24. }
  25. } catch (InterruptedException e) {
  26. e.printStackTrace();
  27. }
  28. return result;
  29. }
  30.  
  31. public static void main(String[] args) {
  32. long start = System.currentTimeMillis();
  33. Result r = new Result("xSharp");// 构造测试数据
  34. FutureCallable callable = new FutureCallable(r);
  35. FutureTask<Result> task = new FutureTask<Result>(callable);
  36. // 构造固定大小为一个线程的线程池
  37. ExecutorService executorService = Executors.newFixedThreadPool();
  38. // 执行线程
  39. executorService.execute(task);
  40. System.out.println("执行完毕!");
  41. long curr01 = System.currentTimeMillis();
  42. System.out.println("任务提交后的耗时:" + (curr01 - start) + "毫秒");
  43. try {
  44. for (int i = ;i < ;i++){
  45. Thread.sleep();
  46. System.out.println("数据还在计算中等待中,你可以做别的事情" + i);
  47. }
  48. } catch (InterruptedException e) {
  49. e.printStackTrace();
  50. }
  51.  
  52. try {
  53. System.out.println("打印结果是:" + task.get().getData());
  54. long end = System.currentTimeMillis();
  55. System.out.println("总耗时:" + (end - start) + "毫秒");
  56. } catch (InterruptedException e) {
  57. e.printStackTrace();
  58. } catch (ExecutionException e) {
  59. e.printStackTrace();
  60. }finally{
  61. System.exit();
  62. }
  63. }
  64.  
  65. }

执行结果如下:

  1. 执行完毕!
  2. 任务提交后的耗时:6毫秒
  3. 数据还在计算中等待中,你可以做别的事情0
  4. 数据还在计算中等待中,你可以做别的事情1
  5. 数据还在计算中等待中,你可以做别的事情2
  6. 数据还在计算中等待中,你可以做别的事情3
  7. 数据还在计算中等待中,你可以做别的事情4
  8. 数据还在计算中等待中,你可以做别的事情5
  9. 打印结果是:xSharp:futureCallable0:futureCallable1:futureCallable2:futureCallable3:futureCallable4:futureCallable5:futureCallable6:futureCallable7:futureCallable8:futureCallable9
  10. 总耗时:1010毫秒

这里我对代码做了一些调整,一个是加上了执行时间的统计,一个是我将干其他事情的程序执行时间变短,小于了线程本身执行的时间,这么做的目的是想和下面的程序对比,下面的代码当我执行线程后没有做其他的操作,而是直接获取线程执行的结果,具体代码如下:

  1. package cn.com.futuretest;
  2.  
  3. import java.util.concurrent.Callable;
  4. import java.util.concurrent.ExecutionException;
  5. import java.util.concurrent.ExecutorService;
  6. import java.util.concurrent.Executors;
  7. import java.util.concurrent.FutureTask;
  8.  
  9. public class NioFutureCallable implements Callable<Result> {
  10.  
  11. private Result result; // 操作的数据,模拟一个计算需要很长时间的数据
  12.  
  13. /* 初始化数据 */
  14. public NioFutureCallable(Result result) {
  15. this.result = result;
  16. }
  17.  
  18. @Override
  19. public Result call() throws Exception {
  20. try {
  21. for (int i = ;i < ;i++){
  22. Thread.sleep();// 每隔100毫秒操作一次数据,模拟数据被长时间计算的场景
  23. result.setData(result.getData() + ":" + "NioFutureCallable" + i);
  24. }
  25. } catch (InterruptedException e) {
  26. e.printStackTrace();
  27. }
  28. return result;
  29. }
  30.  
  31. public static void main(String[] args) {
  32. long start = System.currentTimeMillis();
  33. Result r = new Result("xSharp");// 构造测试数据
  34. NioFutureCallable callable = new NioFutureCallable(r);
  35. FutureTask<Result> task = new FutureTask<Result>(callable);
  36. // 构造固定大小为一个线程的线程池
  37. ExecutorService executorService = Executors.newFixedThreadPool();
  38. // 执行线程
  39. executorService.execute(task);
  40. System.out.println("执行完毕!");
  41. long curr01 = System.currentTimeMillis();
  42. System.out.println("任务提交后的耗时:" + (curr01 - start) + "毫秒");
  43.  
  44. /* 第一次获取返回数据 */
  45. try {
  46. System.out.println("第一次打印结果是:" + task.get().getData());
  47. long curr02 = System.currentTimeMillis();
  48. System.out.println("第一次获取结果耗时:" + (curr02 - start) + "毫秒");
  49. } catch (InterruptedException e1) {
  50. e1.printStackTrace();
  51. } catch (ExecutionException e1) {
  52. e1.printStackTrace();
  53. }
  54.  
  55. try {
  56. for (int i = ;i < ;i++){
  57. Thread.sleep();
  58. System.out.println("数据还在计算中等待中,你可以做别的事情" + i);
  59. }
  60. } catch (InterruptedException e) {
  61. e.printStackTrace();
  62. }
  63.  
  64. try {
  65. System.out.println("第二次打印结果是:" + task.get().getData());
  66. long end = System.currentTimeMillis();
  67. System.out.println("总耗时:" + (end - start) + "毫秒");
  68. } catch (InterruptedException e) {
  69. e.printStackTrace();
  70. } catch (ExecutionException e) {
  71. e.printStackTrace();
  72. }finally{
  73. System.exit();
  74. }
  75.  
  76. }
  77.  
  78. }

执行结果如下:

  1. 1 执行完毕!
  2. 2 任务提交后的耗时:7毫秒
  3. 3 第一次打印结果是:xSharp:NioFutureCallable0:NioFutureCallable1:NioFutureCallable2:NioFutureCallable3:NioFutureCallable4:NioFutureCallable5:NioFutureCallable6:NioFutureCallable7:NioFutureCallable8:NioFutureCallable9
  4. 4 第一次获取结果耗时:1009毫秒
  5. 5 数据还在计算中等待中,你可以做别的事情0
  6. 6 数据还在计算中等待中,你可以做别的事情1
  7. 7 数据还在计算中等待中,你可以做别的事情2
  8. 8 数据还在计算中等待中,你可以做别的事情3
  9. 9 数据还在计算中等待中,你可以做别的事情4
  10. 10 数据还在计算中等待中,你可以做别的事情5
  11. 11 数据还在计算中等待中,你可以做别的事情6
  12. 12 数据还在计算中等待中,你可以做别的事情7
  13. 13 数据还在计算中等待中,你可以做别的事情8
  14. 14 数据还在计算中等待中,你可以做别的事情9
  15. 15 第二次打印结果是:xSharp:NioFutureCallable0:NioFutureCallable1:NioFutureCallable2:NioFutureCallable3:NioFutureCallable4:NioFutureCallable5:NioFutureCallable6:NioFutureCallable7:NioFutureCallable8:NioFutureCallable9
  16. 16 总耗时:2012毫秒

我们看到当我们直接获取结果时候,整个主线程都被阻塞了,直到结果返回后才会执行下面的后续操作,这也就是说如果计算还没结束,我们就想获取结果这样整个执行流程都将被阻塞,这点在我们合理使用Future模式时候很重要。

  除了使用FutureTask实现Future模式,我们还可以使用ExecutorService的submit方法直接返回Future对象,Future就和我前面设计的原生Future类似,当我们开始调用时候返回的是一个虚拟结果,其实实际的计算还没有结束,只有等待吗一会儿后结果才会真正的返回,代码如下:

  1. package cn.com.futuretest;
  2.  
  3. import java.util.concurrent.Callable;
  4. import java.util.concurrent.ExecutionException;
  5. import java.util.concurrent.ExecutorService;
  6. import java.util.concurrent.Executors;
  7. import java.util.concurrent.Future;
  8.  
  9. public class RetFutureCallable implements Callable<Result>{
  10.  
  11. private Result result; // 操作的数据,模拟一个计算需要很长时间的数据
  12.  
  13. public RetFutureCallable() {
  14. result = new Result("xSharp");
  15. }
  16.  
  17. @Override
  18. public Result call() throws Exception {
  19. try {
  20. for (int i = ;i < ;i++){
  21. Thread.sleep();// 每隔100毫秒操作一次数据,模拟数据被长时间计算的场景
  22. result.setData(result.getData() + ":" + "RetFutureCallable" + i);
  23. }
  24. } catch (InterruptedException e) {
  25. e.printStackTrace();
  26. }
  27. return result;
  28. }
  29.  
  30. public static void main(String[] args) {
  31. long start = System.currentTimeMillis();
  32. RetFutureCallable callable = new RetFutureCallable();
  33. // 构造固定大小为一个线程的线程池
  34. ExecutorService executorService = Executors.newFixedThreadPool();
  35. // 执行线程
  36. Future<Result> r = executorService.submit(callable);
  37. System.out.println("执行完毕!");
  38. long curr01 = System.currentTimeMillis();
  39. System.out.println("任务提交后的耗时:" + (curr01 - start) + "毫秒");
  40. try {
  41. for (int i = ;i < ;i++){
  42. Thread.sleep();
  43. System.out.println("数据还在计算中等待中,你可以做别的事情" + i);
  44. }
  45. } catch (InterruptedException e) {
  46. e.printStackTrace();
  47. }
  48.  
  49. try {
  50. System.out.println("打印结果是:" + r.get().getData());
  51. long end = System.currentTimeMillis();
  52. System.out.println("总耗时:" + (end - start) + "毫秒");
  53. } catch (InterruptedException e) {
  54. e.printStackTrace();
  55. } catch (ExecutionException e) {
  56. e.printStackTrace();
  57. }finally{
  58. System.exit();
  59. }
  60. }
  61.  
  62. } 

执行结果如下:

  1. 1 执行完毕!
  2. 2 任务提交后的耗时:5毫秒
  3. 3 数据还在计算中等待中,你可以做别的事情0
  4. 4 数据还在计算中等待中,你可以做别的事情1
  5. 5 数据还在计算中等待中,你可以做别的事情2
  6. 6 数据还在计算中等待中,你可以做别的事情3
  7. 7 数据还在计算中等待中,你可以做别的事情4
  8. 8 数据还在计算中等待中,你可以做别的事情5
  9. 9 打印结果是:xSharp:RetFutureCallable0:RetFutureCallable1:RetFutureCallable2:RetFutureCallable3:RetFutureCallable4:RetFutureCallable5:RetFutureCallable6:RetFutureCallable7:RetFutureCallable8:RetFutureCallable9
  10. 10 总耗时:1006毫秒

转自:http://www.cnblogs.com/sharpxiajun/p/5608663.html

线程技术 ☞ Future模式的更多相关文章

  1. Java中的Future模式原理自定义实现

    摘要:Future模式类似于js中的ajax等,是一个异步获取数据的机制,这里我把自己的一些形象理解通过代码实现了一下.该机制可以形象的理解为:调用获取数据的方法,首先获得一个没有装数据的空箱子(这个 ...

  2. 线程笔记:Future模式

    线程技术可以让我们的程序同时做多件事情,线程的工作模式有很多,常见的一种模式就是处理网站的并发,今天我来说说线程另一种很常见的模式,这个模式和前端里的ajax类似:浏览器一个主线程执行javascri ...

  3. 深入理解[Future模式]原理与技术

    1.Future模式 Future模式和多线程技术密切相关,可以说是利用多线程技术优化程序的一个实例. 在程序设计中,当某一段程序提交了一个请求,期望得到一个答复.但非常不幸的是,服务程序对这个请求的 ...

  4. Java线程池(Callable+Future模式)

    转: Java线程池(Callable+Future模式) Java线程池(Callable+Future模式) Java通过Executors提供四种线程池 1)newCachedThreadPoo ...

  5. java future模式 所线程实现异步调用(转载

    java future模式 所线程实现异步调用(转载) 在多线程交互的中2,经常有一个线程需要得到另个一线程的计算结果,我们常用的是Future异步模式来加以解决.Future顾名思意,有点像期货市场 ...

  6. 架构师养成记--9.future模式讲解

    什么是future模式呢?解释这个概念之前我们先来了解一个场景吧,财务系统的结账功能,这个功能可能是每个月用一次,在这一个月中相关的数据量已经积累得非常大,这一个功能需要调用好几个存储过程来完成.假如 ...

  7. Future模式

    Future模式简介 Future模式有点类似于网上购物,在你购买商品,订单生效之后,你可以去做自己的事情,等待商家通过快递给你送货上门.Future模式就是,当某一程序提交请求,期望得到一个答复.但 ...

  8. 闲谈Future模式-订蛋糕

    一. Future模式简介 Future有道翻译:n. 未来:前途:期货:将来时.我觉得用期货来解释比较合适.举个实际生活中例子来说吧,今天我女朋友过生日,我去蛋糕店准备给女朋友定个大蛋糕,超级大的那 ...

  9. java Future 模式

    考慮這樣一個情況,使用者可能快速翻頁瀏覽文件中,而圖片檔案很大,如此在瀏覽到有圖片的頁數時,就會導致圖片的載入,因而造成使用者瀏覽文件時會有停頓 的現象,所以我們希望在文件開啟之後,仍有一個背景作業持 ...

随机推荐

  1. DevOps - Development And Operations

    简介: 研发运维一体化 相关资料: 关于DevOps你必须知道的11件事 我眼中的DevOps DevOps 门户 docker for dotnet系列 docker4dotnet #1 前世今生 ...

  2. java design

    http://www.austintek.com/mvc/ http://msdn.microsoft.com/zh-cn/magazine/cc163419.aspx http://www.croc ...

  3. K Smallest Sums

    uva11997:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_prob ...

  4. hdu 5147 Sequence II

    http://acm.hdu.edu.cn/showproblem.php?pid=5147 题意:问有多少个这样的四元组(a,b,c,d),满足条件是 1<=a<b<c<d; ...

  5. Android 开机自启动

    首先实现开机自启动: 第一步创建一个广播接收者,如MyBootBroadcastReceiver.java package com.example; import android.content.Br ...

  6. 数据结构算法集---C++语言实现

    //数据结构算法集---C++语言实现 //各种类都使用模版设计,可以对各种数据类型操作(整形,字符,浮点) /////////////////////////// // // // 堆栈数据结构 s ...

  7. SRM 397(1-250pt)

    题意:对于一个长度n的数列(由1-n组成,n <= 8),每次操作可以reverse k个连续的数.问最少多少次操作可以将该数列转化成递增的数列. 解法:就是一个BFS.只是由于最开始学习BFS ...

  8. redmine安装插件流程

    1.redmine用一键安装即可2.进入C:\Bitnami\redmine-3.1.1-1\,执行use_redmine.exe,进入dos系统 不能用cmd进入.3.把文件拷贝到C:\Bitnam ...

  9. Vs 2008 对 OpenMP 的 支持 以及 OpenMP的环境变量及库函数

    Visual C++® 2008对OpenMP的支持 VC++2008根据项目属性配置的指示进行 /openmp编译器切换,当配置了OpenMP支持后,编译器会提供_OPENMP定义,可以使用#ifd ...

  10. Android 免费短信获取国家列表和国家代码

    StringBuffer str = new StringBuffer(); for (Map.Entry<Character, ArrayList<String[]>> en ...