多线程之Future模式
详细参见葛一名老师的《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模式的更多相关文章
- java多线程之Future和FutureTask
Executor框架使用Runnable 作为其基本的任务表示形式.Runnable是一种有局限性的抽象,然后可以写入日志,或者共享的数据结构,但是他不能返回一个值. 许多任务实际上都是存在延迟计算的 ...
- Java多线程之Future与FutureTask
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6561154.html 一:Future 在使用实现Callable创建线程时,call()方法是有返回值的. ...
- C++11多线程之future(一)
// ConsoleApplication5.cpp : 定义控制台应用程序的入口点. #include "stdafx.h" #include<random> #in ...
- Java线程之Callable和Future
本篇说明的是Callable和Future,它俩很有意思的,一个产生结果,一个拿到结果. Callable接口类似于Runnable,从名字就可以看出来了,但是Runnable不会返回结 ...
- 并发编程之Callable异步,Future模式
Callable 在Java中,创建线程一般有两种方式,一种是继承Thread类,一种是实现Runnable接口.然而,这两种方式的缺点是在线程任务执行结束后,无法获取执行结果.我们一般只能采用共享变 ...
- 多线程之RunLoop
*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...
- Java多线程Future模式
Java多线程Future模式有些类似于Ajax的异步请求Future模式的核心在于:去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑 假设服务器的处理某个业务,该业务可以分 ...
- JAVA多线程之volatile 与 synchronized 的比较
一,volatile关键字的可见性 要想理解volatile关键字,得先了解下JAVA的内存模型,Java内存模型的抽象示意图如下: 从图中可以看出: ①每个线程都有一个自己的本地内存空间--线程栈空 ...
- WebAPI调用笔记 ASP.NET CORE 学习之自定义异常处理 MySQL数据库查询优化建议 .NET操作XML文件之泛型集合的序列化与反序列化 Asp.Net Core 轻松学-多线程之Task快速上手 Asp.Net Core 轻松学-多线程之Task(补充)
WebAPI调用笔记 前言 即时通信项目中初次调用OA接口遇到了一些问题,因为本人从业后几乎一直做CS端项目,一个简单的WebAPI调用居然浪费了不少时间,特此记录. 接口描述 首先说明一下,基于 ...
随机推荐
- Python一些字符串判断和转换
设s是字符串: s.isalnum() 判断所有字符都是数字或者字母 s.isalpha() 判断所有字符都是字母 s.isdigit() 判断所有字符都是数字 s.islower() ...
- fork出的子进程和父进程的继承关系【转载】
[原文地址]http://blog.163.com/dengjingniurou@126/blog/static/53989196200962924412524/ fork出的子进程和父进程的继承关系 ...
- 10-C语言函数
目录: 一.函数 二.return与exit关键字 三.递归与递推 回到顶部 一.函数 1 函数由函数名.返回值.形参.函数体组成. 函数的使用分三个步骤:声明.定义.调用 2 语法格式: 返回值类型 ...
- 读书笔记: nodejs API 参考
>> bufferBuffer对象是全局对象Buffer支持的编码方式:ascii, utf8, base64, binarynew Buffer(size)new Buffer(arra ...
- Qt官方开发环境生成的exe发布方式--使用windeployqt(windeployqt是单独的程序,放在低版本qt4目录下也可以运行的)
Qt 官方开发环境使用的动态链接库方式,在发布生成的exe程序时,需要复制一大堆 dll,如果自己去复制dll,很可能丢三落四,导致exe在别的电脑里无法正常运行.因此 Qt 官方开发环境里自带了一个 ...
- 关于 OnCloseQuery: 顺序、不能关机等(所有的windows的广播消息都是逐窗口传递的)——如果一个窗体的OnCloseQuery事件中如果写了代码那么WM_QUERYENDSESSION消息就传不过去了msg.result会返回0,关机事件也就停止了
系统关闭窗体的事件顺序为: OnCloseQuery ----> OnClose ----> OnDestroy 下面的代码说明问题: unit Unit3; interface uses ...
- HDU 1147 Pick-up sticks
题解:每放一根棍子,都判断一下它与它前面的且在顶端的棍子是否相交,相交的话则将相应的棍子从解空间中除去. #include <cstdio> const double eps=1e-14; ...
- Oracle如何实现跨数据库查询
转发:http://www.linuxidc.com/Linux/2012-02/53974.htm 实现结果:在一个数据库中某个用户下编写一个存储过程,在存储过程中使用DBLINK连接另一个数据库, ...
- html 7大知识点
HTML是web前端开发的基础,学习前端的人都是先从html学起的. 关于HTML有一些必备的知识点,这些知识点都是HTML中最基本的内容,也是前端面试最常问的知识点. 1.网页结构网页结构一般都包含 ...
- 1724: [Usaco2006 Nov]Fence Repair 切割木板( 贪心 )
倒过来看 , 每次总是选择最短的两块木板合并 , 用heap维护 ------------------------------------------------------------------- ...