Java多线程编程中,常用的多线程设计模式包括:Future模式、Master-Worker模式、Guarded Suspeionsion模式、不变模式和生产者-消费者模式等。这篇文章主要讲述Future模式,关于其他多线程设计模式的地址如下:
关于其他多线程设计模式的地址如下:
关于Master-Worker模式的详解: Java多线程编程中Master-Worker模式的详解
关于Guarded Suspeionsion模式的详解: Java多线程编程中Guarded Suspeionsion模式的详解
关于不变模式的详解: Java多线程编程中不变模式的详解
关于生产者-消费者模式的详解:生产者-消费者模式Java详解

1. Future模式核心思想

Future模式的核心在于:去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑(根据《Java程序性能优化》)。

Future模式有点类似于商品订单。在网上购物时,提交订单后,在收货的这段时间里无需一直在家里等候,可以先干别的事情。类推到程序设计中时,
当提交请求时,期望得到答复时,如果这个答复可能很慢。传统的时一直等待到这个答复收到时再去做别的事情,但如果利用Future设计模式就无需等待答复
的到来,在等待答复的过程中可以干其他事情。

例如如下的请求调用过程时序图。当call请求发出时,需要很长的时间才能返回。左边的图需要一直等待,等返回数据后才能继续其他操作;而右边的
Future模式的图中客户端则无需等到可以做其他的事情。服务器段接收到请求后立即返回结果给客户端,这个结果并不是真实的结果(是虚拟的结果),也就
是先获得一个假数据,然后执行其他操作。

 

2. Future模式Java实现

Client的实现

Client主要完成的功能包括:1. 返回一个FutureData;2.开启一个线程用于构造RealData。

  1. public class Client {
  2. public Data request(final String string) {
  3. final FutureData futureData = new FutureData();
  4.  
  5. new Thread(new Runnable() {
  6. @Override
  7. public void run() {
  8. //RealData的构建很慢,所以放在单独的线程中运行
  9. RealData realData = new RealData(string);
  10. futureData.setRealData(realData);
  11. }
  12. }).start();
  13.  
  14. return futureData; //先直接返回FutureData
  15. }
  16. }

Data的实现

无论是FutureData还是RealData都实现该接口。

  1. public interface Data {
  2. String getResult() throws InterruptedException;
  3. }

FutureData的实现

FutureData是Future模式的关键,它实际上是真实数据RealData的代理,封装了获取RealData的等待过程。

  1. //FutureData是Future模式的关键,它实际上是真实数据RealData的代理,封装了获取RealData的等待过程
  2. public class FutureData implements Data {
  3. RealData realData = null; //FutureData是RealData的封装
  4. boolean isReady = false; //是否已经准备好
  5.  
  6. public synchronized void setRealData(RealData realData) {
  7. if(isReady)
  8. return;
  9. this.realData = realData;
  10. isReady = true;
  11. notifyAll(); //RealData已经被注入到FutureData中了,通知getResult()方法
  12. }
  13.  
  14. @Override
  15. public synchronized String getResult() throws InterruptedException {
  16. if(!isReady) {
  17. wait(); //一直等到RealData注入到FutureData中
  18. }
  19. return realData.getResult();
  20. }
  21. }

RealData的实现

RealData是最终需要使用的数据,它的构造函数很慢。

  1. public class RealData implements Data {
  2. protected String data;
  3.  
  4. public RealData(String data) {
  5. //利用sleep方法来表示RealData构造过程是非常缓慢的
  6. try {
  7. Thread.sleep(1000);
  8. } catch (InterruptedException e) {
  9. e.printStackTrace();
  10. }
  11. this.data = data;
  12. }
  13.  
  14. @Override
  15. public String getResult() {
  16. return data;
  17. }
  18. }

测试运行

主函数主要负责调用Client发起请求,并使用返回的数据。

  1. public class Application {
  2. public static void main(String[] args) throws InterruptedException {
  3. Client client = new Client();
  4. //这里会立即返回,因为获取的是FutureData,而非RealData
  5. Data data = client.request("name");
  6. //这里可以用一个sleep代替对其他业务逻辑的处理
  7. //在处理这些业务逻辑过程中,RealData也正在创建,从而充分了利用等待时间
  8. Thread.sleep(2000);
  9. //使用真实数据
  10. System.out.println("数据="+data.getResult());
  11. }
  12. }

3. Future模式的JDK内置实现

由于Future是非常常用的多线程设计模式,因此在JDK中内置了Future模式的实现。这些类在java.util.concurrent包
里面。其中最为重要的是FutureTask类,它实现了Runnable接口,作为单独的线程运行。在其run()方法中,通过Sync内部类调用
Callable接口,并维护Callable接口的返回对象。当使用FutureTask.get()方法时,将返回Callable接口的返回对象。
同样,针对上述的实例,如果使用JDK自带的实现,则需要作如下调整。

首先,Data接口和FutureData就不需要了,JDK帮我们实现了。

其次,RealData改为这样:

  1. import java.util.concurrent.Callable;
  2.  
  3. public class RealData implements Callable {
  4. protected String data;
  5.  
  6. public RealData(String data) {
  7. this.data = data;
  8. }
  9.  
  10. @Override
  11. public String call() throws Exception {
  12. //利用sleep方法来表示真是业务是非常缓慢的
  13. try {
  14. Thread.sleep(1000);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. return data;
  19. }
  20. }

最后,在测试运行时,这样调用:

  1. import java.util.concurrent.ExecutorService;
  2. import java.util.concurrent.Executors;
  3. import java.util.concurrent.FutureTask;
  4.  
  5. public class Application {
  6. public static void main(String[] args) throws Exception {
  7. FutureTask futureTask =
  8. new FutureTask(new RealData("name"));
  9. ExecutorService executor =
  10. Executors.newFixedThreadPool(1); //使用线程池
  11. //执行FutureTask,相当于上例中的client.request("name")发送请求
  12. executor.submit(futureTask);
  13. //这里可以用一个sleep代替对其他业务逻辑的处理
  14. //在处理这些业务逻辑过程中,RealData也正在创建,从而充分了利用等待时间
  15. Thread.sleep(2000);
  16. //使用真实数据
  17. //如果call()没有执行完成依然会等待
  18. System.out.println("数据=" + futureTask.get());
  19. }
  20. }

本文完。转载请注明出处。

参考文献
葛一鸣,Java程序性能优化.清华大学出版社.

转自 http://www.2cto.com/kf/201411/351903.html

Java多线程编程中Future模式的详解<转>的更多相关文章

  1. Java多线程编程中Future模式的详解

    Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...

  2. java并发编程(七)synchronized详解

    Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码.     一.当两个并发线程访问同一个对象object中的这个synchronized( ...

  3. Java多线程(三)—— synchronized关键字详解

    一.多线程的同步 1.为什么要引入同步机制 在多线程环境中,可能会有两个甚至更多的线程试图同时访问一个有限的资源.必须对这种潜在资源冲突进行预防. 解决方法:在线程使用一个资源时为其加锁即可. 访问资 ...

  4. Java并发编程基础--基本线程方法详解

    什么是线程 线程是操作系统调度的最小单位,一个进程中可以有多个线程,这些线程可以各自的计数器,栈,局部变量,并且能够访问共享的内存变量.多线程的优势是可以提高响应时间和吞吐量. 使用多线程 一个进程正 ...

  5. java多线程同步以及线程间通信详解&消费者生产者模式&死锁&Thread.join()(多线程编程之二)

    本篇我们将讨论以下知识点: 1.线程同步问题的产生 什么是线程同步问题,我们先来看一段卖票系统的代码,然后再分析这个问题: package com.zejian.test; /** * @author ...

  6. 详解Java多线程编程中LockSupport类的线程阻塞用法

    LockSupport类是Java6(JSR166-JUC)引入的一个类,提供了基本的线程同步原语.LockSupport实际上是调用了Unsafe类里的函数,归结到Unsafe里,只有两个函数: p ...

  7. 详解Java多线程编程中LockSupport

    LockSupport是用来创建锁和其他同步类的基本线程阻塞原语. LockSupport中的park() 和 unpark() 的作用分别是阻塞线程和解除阻塞线程,而且park()和unpark() ...

  8. 【转】Java多线程编程中易混淆的3个关键字( volatile、ThreadLocal、synchronized)总结

    概述 最近在看<ThinKing In Java>,看到多线程章节时觉得有一些概念比较容易混淆有必要总结一下,虽然都不是新的东西,不过还是蛮重要,很基本的,在开发或阅读源码中经常会遇到,在 ...

  9. Java多线程编程——生产者-消费者模式(1)

    生产者-消费者模式在生活中非常常见.就拿我们去餐馆吃饭为例.我们会遇到以下两种情况: 1.厨师-客人 如下图所示,生产者.消费者直接进行交互. 生产者生产出产品后,通知消费者:消费者消费后,通知生产者 ...

随机推荐

  1. 小而美的ghost driver

    做过selenium自动化项目的同学应该都遇到过这样的问题:测试用例太多,运行速度过慢导致团队成员怨声载道. 于是便有了selenium grid和多线程运行selenium测试用例的方法.这些方法各 ...

  2. dart --- 更符合程序员编程习惯的javascript替代者

    dart是google在2011年推出的一门语言,提供较为丰富的lib,并支持将代码转变为javascript,其demo code 和 demo app 也是以web前端代码来展示的. 其语言特性较 ...

  3. [转]Greenplum的工作负载及资源管理

    工作负载及资源管理 查询分析-查看EXPLAIN输出 EXPLAIN输出一个计划为节点组成的树 每个节点表示一个独立的操作 计划应该从下向上读,每个节点得到的记录向上传递 成本评估项: cost - ...

  4. Java 8 Streams filter examples

    1. Streams filter() and collect() package com.mkyong.java8; import java.util.Arrays;import java.util ...

  5. python selenium 使用unittest 示例

    python selenium 使用unittest 示例 并等待某个元素示例 from selenium.webdriver.support.ui import WebDriverWait from ...

  6. 安装Flume的时候出现File Channel transaction capacity cannot be greater than the capacity of the channel capacity -解决方案 摘自网络

    部署flume集群时,在启动collector服务器没报错,启动agent服务器报错: File Channel transaction capacity cannot be greater than ...

  7. gitlab runner 配置

    gitlab runnerhttps://scarletsky.github.io/2016/07/29/use-gitlab-ci-for-continuous-integration/https: ...

  8. linux c select函数使用求解释

          代码非常easy,就是发送c语言发送http请求.但 i= read(sockfd, buf, BUFSIZE-1); 能够正常执行,  替换为i= Read(sockfd, buf, B ...

  9. JSP中四种传递参数中文乱码问题

    查看来源:http://blog.csdn.net/hackerain/article/details/6776083

  10. (转载)javascript将base64编码的图片数据转换为file并提交

    /** * @param base64Codes * 图片的base64编码 */ function sumitImageFile(base64Codes){ var form=document.fo ...