Java多线程Future模式
Java多线程Future模式有些类似于Ajax的异步请求
Future模式的核心在于:去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑
假设服务器的处理某个业务,该业务可以分成AB两个过程,并且AB两个过程之间不需要彼此的返回结果
A过程需要1秒钟,B过程需要2秒钟,主线程其他操作2秒钟
按照正常编写,程序大概需要执行5秒
如果按照Future模式只需要执行2秒(取其中运行时间最久的线程的运行时间)
Future模式的核心实现在于两个方面 1.多线程运行
主线程采用多线的方式,运行几个业务无关的任务来节省主线的等待时间。
2.锁的锁定和释放
子线程执行指定的任务时,需要保证主线程能正确的获取子线程的返回数据
这里分两种情况
(1)子线程的运行时间要大于主线程处理其他业务的时间,此时主线程需要获取子线程的返回值,而子线程却还没有执行完毕,
所以在这个时候需要让主线程进入等待。子线程执行完毕以后立刻唤醒主线程。
(2)子线程的运行时间小于主线处理其他业务的时间,此时无需要等待。 知识要点:
1、wait(),notify()需要和synchronized一块使用,去掉会报 java.lang.IllegalMonitorStateException
1>当前线程不含有当前对象的锁资源的时候,调用obj.wait()方法;
2>当前线程不含有当前对象的锁资源的时候,调用obj.notify()方法。
3>当前线程不含有当前对象的锁资源的时候,调用obj.notifyAll()方法。
2、wait()方法会释放锁
Service模拟服务器处理业务的过程
package future; import java.util.Date; /**
* 服务器
*
* @author wpy
*
*/
public class Service {
/**
* 1.服务器的处理某个业务,该业务可以分成AB两个过程,并且AB两个过程之间不需要彼此的返回结果
* 2.A过程需要1秒钟,B过程需要2秒钟,主线程其他操作2秒钟
*
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
Service service = new Service();
long notUseFuture = service.notUseFuture(); System.out.println("==============================");
long useFuture = service.useFuture(); System.out.println("==============================");
System.out.println("notUseFuture整个业务耗时"+notUseFuture);
System.out.println("useFuture整个业务耗时"+useFuture);
} public long useFuture() throws InterruptedException {
Date startOn = new Date(); String name = Thread.currentThread().getName();
final FutureDate<String> futureDateA = new FutureDate<>();
final FutureDate<String> futureDateB = new FutureDate<>(); Thread a = new Thread(new Runnable() { @Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + ":任务A开始执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
futureDateA.setData(name + ":任务A执行结果");
System.out.println(name + ":任务A执行结束");
}
}, "线程A"); Thread b = new Thread(new Runnable() { @Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + ":任务B开始执行");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
futureDateB.setData(name + ":任务B执行结果");
System.out.println(name + ":任务B执行结束");
}
}, "线程B"); Date before = new Date();
a.start();
b.start();
Date after = new Date();
System.out.println(name + ":a,b阻塞主线程时间:"
+ (after.getTime() - before.getTime())); // 假设其他业务执行两秒钟
Thread.sleep(2000); before = new Date();
String dataA = futureDateA.getData();
after = new Date();
System.out.println(name + ":获取A线程结果时间:"
+ (after.getTime() - before.getTime())); before = new Date();
String dataB = futureDateB.getData();
after = new Date();
System.out.println(name + ":获取线程结果时间:"
+ (after.getTime() - before.getTime())); System.out.println(name + ":A线程结果:" + dataA);
System.out.println(name + ":B线程结果:" + dataB);
Date endOn = new Date(); /*System.out.println(name + "整个业务耗时"
+ (endOn.getTime() - startOn.getTime()));*/
return endOn.getTime() - startOn.getTime();
} public long notUseFuture() throws InterruptedException {
Date startOn = new Date(); // 任务A
String name = Thread.currentThread().getName();
System.out.println(name + ":任务A开始执行");
Thread.sleep(1000);
System.out.println(name + ":任务A执行结束"); // 任务B
System.out.println(name + ":任务B开始执行");
Thread.sleep(3000);
System.out.println(name + ":任务B执行结束"); // 主线程其他操作
Thread.sleep(2000); Date endOn = new Date();
return endOn.getTime() - startOn.getTime();
}
}
封装的FutrueData类
package future; /**
* 用户获取异步任务执行结果
* @author wpy
*
*/
public class FutureDate<T> {
private boolean isReady = false;
private T data; /**
* 异步任务执行完毕后会通过此方法将执行结果传递给data;
* @param data
*/
public synchronized void setData(T data){
if(isReady){
return;
}
this.data = data;
isReady = true;
notify();
} /**
* 如果数据没有加载完毕,线程积蓄等待
* wait()会释放锁
* @return
* @throws InterruptedException
*/
public synchronized T getData() throws InterruptedException{
if(!isReady){
wait();
}
return data;
} }
执行结果
main:任务A开始执行
main:任务A执行结束
main:任务B开始执行
main:任务B执行结束
==============================
main:a,b阻塞主线程时间:0
线程A:任务A开始执行
线程B:任务B开始执行
线程A:任务A执行结束
main:获取A线程结果时间:0
线程B:任务B执行结束
main:获取线程结果时间:1001
main:A线程结果:线程A:任务A执行结果
main:B线程结果:线程B:任务B执行结果
==============================
notUseFuture整个业务耗时6001
useFuture整个业务耗时3006
JDK封装的Future简单使用
package test; import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask; public class TestFuture { public static void main(String[] args) throws InterruptedException, ExecutionException { Callable<Object> callable = new Callable<Object>() { @Override
public Object call() throws Exception {
System.out.println(Thread.currentThread().getName()+":正在构造数据");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+":构造数据数据完毕");
return "结果";
}
};
Date before = new Date();
FutureTask<Object> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start(); Thread.sleep(1000);
Date after = new Date();
System.out.println((after.getTime() - before.getTime())/1000); before = new Date();
System.out.println(Thread.currentThread().getName()+":主程序准备获取结果");
Object object = futureTask.get();
after = new Date();
System.out.println((after.getTime() - before.getTime())/1000); System.out.println(object);
}
}
Java多线程Future模式的更多相关文章
- 彻底理解Java的Future模式
先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材.网上购买厨具比较方便,食材去超市买更放心. 实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材.所以,在主线程里面另起一个子线 ...
- Java多线程--并行模式与算法
Java多线程--并行模式与算法 单例模式 虽然单例模式和并行没有直接关系,但是我们经常会在多线程中使用到单例.单例的好处有: 对于频繁使用的对象可以省去new操作花费的时间: new操作的减少,随之 ...
- Java多线程Master-Worker模式
Java多线程Master-Worker模式,多适用于需要大量重复工作的场景中. 例如:使用Master-Worker计算0到100所有数字的立方的和 1.Master接收到100个任务,每个任务需要 ...
- Java多线程编程模式实战指南(三):Two-phase Termination模式
停止线程是一个目标简单而实现却不那么简单的任务.首先,Java没有提供直接的API用于停止线程.此外,停止线程时还有一些额外的细节需要考虑,如待停止的线程处于阻塞(等待锁)或者等待状态(等待其它线程) ...
- java多线程编程模式
前言 区别于java设计模式,下面介绍的是在多线程场景下,如何设计出合理的思路. 不可变对象模式 场景 1. 对象的变化频率不高 每一次变化就是一次深拷贝,会影响cpu以及gc,如果频繁操作会影响性能 ...
- Java多线程编程模式实战指南(三):Two-phase Termination模式--转载
本文由本人首次发布在infoq中文站上:http://www.infoq.com/cn/articles/java-multithreaded-programming-mode-two-phase-t ...
- Java多线程编程模式实战指南(二):Immutable Object模式--转载
本文由本人首次发布在infoq中文站上:http://www.infoq.com/cn/articles/java-multithreaded-programming-mode-immutable-o ...
- 多线程--future模式初体验
第一次使用多线程,虽然理解的不是很透彻,但是也值得记录下.用的是future模式. 创建个线程池:private ExecutorService cachedThreadPool = Executor ...
- Java 多线程 - Future
Java中Future的使用场景和解析 https://blog.csdn.net/hongtaolong/article/details/83349705 (细看!!!)
随机推荐
- 【Linux笔记(002) 】-- centos7 文档操作基本命令
一.cd -- ChangeDirectory a) 切换到 /DemoLM/ 文件夹 b) 回到用户 Home 根目录:是哪个账户登录的就会进入哪个用户的根目录 二.pwd -- PrintWork ...
- 终极解决方案 at org.apache.jsp.index_jsp._jspInit(index_jsp.java:22) 报空指针
java.lang.NullPointerException at org.apache.jsp.index_jsp._jspInit(index_jsp.java:22) 出现这种问题,可能有多方 ...
- Linux入门之常用命令(7)压缩
compress filename 压缩 -d解压缩 *.Z bzip -d解压缩 -z压缩 *.bz2 bzcat filename .bz2 读取压缩文件内容 gzip -d解压缩 -#压 ...
- 深入浅出数据结构C语言版(22)——排序决策树与桶式排序
在(17)中我们对排序算法进行了简单的分析,并得出了两个结论: 1.只进行相邻元素交换的排序算法时间复杂度为O(N2) 2.要想时间复杂度低于O(N2),算法必须进行远距离的元素交换 而今天,我们将对 ...
- 每周分享之 二 http协议(1)
本次分享http协议,共分为三部分,这是第一部分,主要讲解http的发展历程,各个版本,以及各个版本的特点. 一:http/0.9 最早版本是1991年发布的0.9版.该版本极其简单,只有一个命令GE ...
- hdu4686 Arc of Dream 2013 Multi-University Training Contest 9矩阵快速幂
Arc of Dream Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others) Tot ...
- 【笔记】Kali linux的安装 和 一些使用前的准备工作(原创+转载)
该博文只记录笔者的蛇皮使用经历,纯新手= =,可能借鉴意义也可能没有(T _ T),侵删. 目录 kali linux 在个人计算机和在VirtualBox下的安装 kali linux 使用前准备工 ...
- Angular4 后台管理系统搭建(10) - 做一个通用的可跨域上传文件的组件
写的很慢,不知不觉这是第十篇了.但是我其他事情太多,只能抽空写下.现在angular4或angular2流行的上传方式是ng2-file-upload.它的功能很强大.但是我没有配置成可以跨域上传的. ...
- jquery访问浏览器本地存储cookie,localStorage和sessionStorage
前言:cookie,localStorage和sessionStorage都是浏览器本地存储数据的地方,其用法不尽相同:总结一下基本的用法. 一.cookie 定义: 存储在本地,容量最大4k,在同源 ...
- web前端开发初学者必看的学习路线(附思维导图)
很多同学想学习WEB前端开发,虽然互联网有很多的教程.网站.书籍,可是却又不知从何开始如何选取.看完网友高等游民白乌鸦无私分享的原标题为<写给同事的前端学习路线>这篇文章,相信你会有所收获 ...