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);
	}
}

  

时间: 2024-10-10 13:18:05

Java多线程Future模式的相关文章

彻底理解Java的Future模式(转)

先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材.网上购买厨具比较方便,食材去超市买更放心. 实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材.所以,在主线程里面另起一个子线程去网购厨具. 但是,子线程执行的结果是要返回厨具的,而run方法是没有返回值的.所以,这才是难点,需要好好考虑一下. 模拟代码1: package test; public class CommonCook { public static void main(String[] args) thro

Java多线程Master-Worker模式

Java多线程Master-Worker模式,多适用于需要大量重复工作的场景中. 例如:使用Master-Worker计算0到100所有数字的立方的和 1.Master接收到100个任务,每个任务需要0到100中每个数字的立方,这里为了效果,每个任务再sleep一秒, Master需要将这些任务放到一个支持高并发的非阻塞队列queue中如:ConcurrentLinkedQueue<E>. 2.Master创建10个worker去执行这100个任务,并准备一个支持高并发且线程安全的hashMa

Java多线程编程模式实战指南(三):Two-phase Termination模式--转载

本文由本人首次发布在infoq中文站上:http://www.infoq.com/cn/articles/java-multithreaded-programming-mode-two-phase-termination.转载请注明作者: 黄文海 出处:http://viscent.iteye.com. 停止线程是一个目标简单而实现却不那么简单的任务.首先,Java没有提供直接的API用于停止线程.此外,停止线程时还有一些额外的细节需要考虑,如待停止的线程处于阻塞(等待锁)或者等待状态(等待其它

Java多线程编程模式实战指南(二):Immutable Object模式--转载

本文由本人首次发布在infoq中文站上:http://www.infoq.com/cn/articles/java-multithreaded-programming-mode-immutable-object.转载请注明作者: 黄文海 出处:http://viscent.iteye.com. 多线程共享变量的情况下,为了保证数据一致性,往往需要对这些变量的访问进行加锁.而锁本身又会带来一些问题和开销.Immutable Object模式使得我们可以在不使用锁的情况下,既保证共享变量访问的线程安

Java多线程编程模式实战指南(三):Two-phase Termination模式

停止线程是一个目标简单而实现却不那么简单的任务.首先,Java没有提供直接的API用于停止线程.此外,停止线程时还有一些额外的细节需要考虑,如待停止的线程处于阻塞(等待锁)或者等待状态(等待其它线程).尚有未处理完的任务等.本文介绍的Two-phase Termination模式提供了一种通用的用于优雅地停止线程的方法. Two-phase Termination模式简介 Java并没有提供直接的API用于停止线程.Two-phase Termination模式通过将停止线程这个动作分解为准备阶

Java多线程编程模式实战指南(一):Active Object模式--转载

本文由黄文海首次发布在infoq中文站上:http://www.infoq.com/cn/articles/Java-multithreaded-programming-mode-active-object-part1 .转载请注明作者: 黄文海 出处:http://viscent.iteye.com. Active Object模式简介 Active Object模式是一种异步编程模式.它通过对方法的调用与方法的执行进行解耦来提高并发性.若以任务的概念来说,Active Object模式的核心

Java多线程编程模式实战指南之Promise模式

Promise模式简介(转) Promise模式是一种异步编程模式 .它使得我们可以先开始一个任务的执行,并得到一个用于获取该任务执行结果的凭据对象,而不必等待该任务执行完毕就可以继续执行其他操作.等到我们需要该任务的执行结果时,再调用凭据对象的相关方法来获取.这样就避免了不必要的等待,增加了系统的并发性.这好比我们去小吃店,同时点了鸭血粉丝汤和生煎包.当我们点餐付完款后,我们拿到手的其实只是一张可借以换取相应食品的收银小票(凭据对象)而已,而不是对应的实物.由于鸭血粉丝汤可以较快制作好,故我们

Java多线程编程模式实战指南一:Active Object模式(上)

Active Object模式简介 Active Object模式是一种异步编程模式.它通过对方法的调用与方法的执行进行解耦来提高并发性.若以任务的概念来说,Active Object模式的核心则是它允许任务的提交(相当于对异步方法的调用)和任务的执行(相当于异步方法的真正执行)分离.这有点类似于System.gc()这个方法:客户端代码调用完gc()后,一个进行垃圾回收的任务被提交,但此时JVM并不一定进行了垃圾回收,而可能是在gc()方法调用返回后的某段时间才开始执行任务--回收垃圾.我们知

Java多线程编程模式实战指南一:Active Object模式(下)

Active Object模式的评价与实现考量 Active Object模式通过将方法的调用与执行分离,实现了异步编程.有利于提高并发性,从而提高系统的吞吐率. Active Object模式还有个好处是它可以将任务(MethodRequest)的提交(调用异步方法)和任务的执行策略(Execution Policy)分离.任务的执行策略被封装在Scheduler的实现类之内,因此它对外是不"可见"的,一旦需要变动也不会影响其它代码,降低了系统的耦合性.任务的执行策略可以反映以下一些