详细参见葛一名老师的《Java程序性能优化》

Futrue模式:对于多线程,如果线程A要等待线程B的结果,那么线程A没必要等待B,直到B有结果,可以先拿到一个未来的Future,等B有结果是再取真实的结果。

 在多线程中经常举的一个例子就是:网络图片的下载,刚开始是通过模糊的图片来代替最后的图片,等下载图片的线程下载完图片后在替换。而在这个过程中可以做一些其他的事情。

  首先客户端向服务器请求RealSubject,但是这个资源的创建是非常耗时的,怎么办呢?这种情况下,首先返回Client一个FutureSubject,以满足客户端的需求,于此同时呢,Future会通过另外一个Thread 去构造一个真正的资源,资源准备完毕之后,在给future一个通知。如果客户端急于获取这个真正的资源,那么就会阻塞客户端的其他所有线程,等待资源准备完毕。

  公共数据接口,FutureData和RealData都要实现。

 public interface Data {
public abstract String getContent();
}

  FutureData,当有线程想要获取RealData的时候,程序会被阻塞。等到RealData被注入才会使用getReal()方法。

 package com.volshell.future;

 public class FutureData implements Data {

     protected RealData realData = null;
protected boolean isReady = false; @Override
public synchronized String getResult() {
// TODO Auto-generated method stub
while (!isReady) {
try {
wait();
} catch (Exception e) {
// TODO: handle exception
}
}
return realData.result;
} public synchronized void setRealData(RealData realData) {
if (isReady)
return;
this.realData = realData;
isReady = true;
notifyAll();
}
}

  真实数据RealData

 package com.volshell.future;

 public class RealData implements Data {
protected String result; public RealData(String para) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10; i++) {
sb.append(para);
try {
Thread.sleep(100);
} catch (Exception e) {
// TODO: handle exception
}
result = sb.toString();
}
} @Override
public String getResult() {
// TODO Auto-generated method stub
return result;
} }

  客户端程序:

 package com.volshell.future;

 public class Client {
public Data request(final String request){
final FutureData future = new FutureData();
new Thread(){
public void run() { RealData reaData = new RealData(request);
future.setRealData(reaData);
};
}.start();
return future;
}
}

  调用者:

 package com.volshell.future;

 public class Main {
public static void main(String[] args) {
Client client = new Client();
Data data = client.request("name");
System.out.println("请求完毕!!");
try {
Thread.sleep(2000);
} catch (Exception e) {
// TODO: handle exception
}
System.out.println("获取的数据:" +data.getResult());
}
}

  调用者请求资源,client.request("name"); 完成对数据的准备

  当要获取资源的时候,data.getResult() ,如果资源没有准备好isReady = false;那么就会阻塞该线程。直到资源获取然后该线程被唤醒。

  今天又重新了解了future模式。

 package com.volshell.future2;

 import java.util.ArrayList;
import java.util.List;
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 FutureTest2 {
private static class Task implements Callable<String> {
@Override
public String call() throws Exception {
// 模拟真实事务的处理过程,这个过程是非常耗时的。
Thread.sleep(5000);
return "call return ";
}
} public static void main(String[] args) throws InterruptedException,
ExecutionException {
List<Future<String>> futures = new ArrayList<Future<String>>();
ExecutorService executorService = Executors.newCachedThreadPool(); System.out.println("已经提交资源申请");
for (int i = 0; i < 10; i++) {
futures.add(executorService.submit(new Task()));
} for (Future<String> future : futures) {
// 判断资源是不是已经准备完毕,准备完毕直接获取。
if (!future.isDone()) {
System.out.println("资源还没有准备好");
}
System.out.println(future.get());
}
executorService.shutdown();
}
}

其中的核心就是Callable中的call方法,这个和Runnable中的run 非常类似。

Runnable和Callable都是接口
不同之处:
1.Callable可以返回一个类型V,而Runnable不可以
2.Callable能够抛出checked exception,而Runnable不可以
3.Runnable是自从java1.1就有了,而Callable是1.5之后才加上去的
4.Callable和Runnable都可以应用于executors。而Thread类只支持Runnable.
上面只是简单的不同,其实这两个接口在用起来差别还是很大的。Callable与executors联合在一起,在任务完成时可立刻获得一个更新了的Future。而Runable却要自己处理

Future接口,一般都是取回Callable执行的状态用的。其中的主要方法:

  • cancel,取消Callable的执行,当Callable还没有完成时
  • get,获得Callable的返回值
  • isCanceled,判断是否取消了
  • isDone,判断是否完成

用Executor来构建线程池,应该要做的事:

1).调用Executors类中的静态方法newCachedThreadPool(必要时创建新
线程,空闲线程会被保留60秒)或newFixedThreadPool(包含固定数量的线程池)等,返回的是一个实现了ExecutorService
接口的ThreadPoolExecutor类或者是一个实现了ScheduledExecutorServiece接口的类对象。

2).调用submit提交Runnable或Callable对象。

3).如果想要取消一个任务,或如果提交Callable对象,那就要保存好返回的Future对象。

4).当不再提交任何任务时,调用shutdown方法

多线程之Future模式的更多相关文章

  1. java多线程之Future和FutureTask

    Executor框架使用Runnable 作为其基本的任务表示形式.Runnable是一种有局限性的抽象,然后可以写入日志,或者共享的数据结构,但是他不能返回一个值. 许多任务实际上都是存在延迟计算的 ...

  2. Java多线程之Future与FutureTask

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6561154.html  一:Future 在使用实现Callable创建线程时,call()方法是有返回值的. ...

  3. C++11多线程之future(一)

    // ConsoleApplication5.cpp : 定义控制台应用程序的入口点. #include "stdafx.h" #include<random> #in ...

  4. Java线程之Callable和Future

    本篇说明的是Callable和Future,它俩很有意思的,一个产生结果,一个拿到结果.        Callable接口类似于Runnable,从名字就可以看出来了,但是Runnable不会返回结 ...

  5. 并发编程之Callable异步,Future模式

    Callable 在Java中,创建线程一般有两种方式,一种是继承Thread类,一种是实现Runnable接口.然而,这两种方式的缺点是在线程任务执行结束后,无法获取执行结果.我们一般只能采用共享变 ...

  6. 多线程之RunLoop

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  7. Java多线程Future模式

    Java多线程Future模式有些类似于Ajax的异步请求Future模式的核心在于:去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑 假设服务器的处理某个业务,该业务可以分 ...

  8. JAVA多线程之volatile 与 synchronized 的比较

    一,volatile关键字的可见性 要想理解volatile关键字,得先了解下JAVA的内存模型,Java内存模型的抽象示意图如下: 从图中可以看出: ①每个线程都有一个自己的本地内存空间--线程栈空 ...

  9. WebAPI调用笔记 ASP.NET CORE 学习之自定义异常处理 MySQL数据库查询优化建议 .NET操作XML文件之泛型集合的序列化与反序列化 Asp.Net Core 轻松学-多线程之Task快速上手 Asp.Net Core 轻松学-多线程之Task(补充)

    WebAPI调用笔记   前言 即时通信项目中初次调用OA接口遇到了一些问题,因为本人从业后几乎一直做CS端项目,一个简单的WebAPI调用居然浪费了不少时间,特此记录. 接口描述 首先说明一下,基于 ...

随机推荐

  1. linux技术框架

    编程语言 一般使用c或者c++ linux使用 鸟哥私房菜 工具使用 代码编辑source insight,代码编译gcc,代码调试gdb,代码编译组织makefile,命令执行shell,文本编辑n ...

  2. C++ 用libcurl库进行http 网络通讯编程

      一.LibCurl基本编程框架libcurl是一个跨平台的网络协议库,支持http, https, ftp, gopher, telnet, dict, file, 和ldap 协议.libcur ...

  3. Cloud Foundry warden container 安全性探讨

    本文将从Cloud Foundry中warden container的几个方面探讨warden container的安全性. 1. warden container互訪 1.1.  互訪原理· 在Cl ...

  4. leetCode解题报告5道题(六)

    题目一: Longest Substring Without Repeating Characters Given a string, find the length of the longest s ...

  5. Java输入输出流(1)

    1.什么是IO Java中I/O操作主要是指使用Java进行输入,输出操作. Java全部的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列.Java的I/O流提供了读 ...

  6. 简单JSONP跨域请求

    JSONP原理:利用<script>标签的src属性实现跨域的请求.可在URL中提供回调函数的名字.后台进过处理后将数据以回调函数参数的形式返回. demo:JSONP请求不同端口的数据 ...

  7. Tableau 群集部署

    由于公司连续两个月月底Tableau服务器过载崩溃,因此有了搭建Tableau服务器群集的想法.目前还在测试阶段,所以做一步写一步了. 目录: 一.安装和配置工作服务器 二.其他参考文档 一. 安装和 ...

  8. 访问Tableau自带的PostgreSQL数据库

    突然发现公司Tableau服务器的数据库大小急剧增加,因此决定直接连上数据库排查.过程记录如下:最后发现有个http_requests 表体积巨大(7G),本来以为是数据缓存什么的.结果是日志问题o( ...

  9. linux账户管理(centos)

    1./etc/passwd 非常详细的/etc/passwd解释 http://luzl.iteye.com/blog/564404 vi /etc/passwd,可以看到如下信息,在最后一行可以看到 ...

  10. C、C++中“*”操作符和“后++”操作符的优先级

    假设有如下的定义 char carr[] = {"test"}; char cp = carr; 那么表达式 *cp++; 的右值是什么呢? 这个表达式在数组遍历的程序中非常常见, ...