• [置顶] JDK-Future 模式和实现


    最近的项目用到了多线程,发现java.util.concurrent.Future蛮好用的。
    像平时,写多线程一般使用Thread/Runnable,直接扔给线程池执行就好了。但是遇到了一些需要获取线程执行结果的情况,就需要使用Callable。对于使用Callable的task,ExecutorService执行后会返回一个Future对象来传递执行结果。
    那这个Future是怎么存放返回值的呢,这个Future有什么值得使用的地方呢。我查了一下,发现原来还专门有个Future模式。

    Future模式

    Future模式在请求发生时,会先产生一个Future凭证给发出请求的客户,它的作用就像是Proxy物件,同时,由一个新的执行线程持续进行目标物件的生成(Thread-Per-Message),真正的目标物件生成之后,将之设定至Future之中,而当客户端真正需要目标物件时,目标物件也已经准备好,可以让客户提取使用。
    结合JDK的Future来看,就是你run线程后,你可以把线程的返回值赋给Future并返回一个Future对象。这时你可以立即拿到这个对象,然后进行下面的逻辑。但是如果你要get这个Future中的线程结果,就会被阻塞直到线程结束。
    就相当于现在的期房,你把手续和钱都交上去了,就可以马上拿到合同,但只有合同没有房子。这个时候你已经是有房一族了,你可以先去买家电买装修(走下面的其他逻辑)。但是你要把家电和装修放进去,就必须等到房子完工(阻塞)。
    这样有一个好处,就是你把处理任务交给线程并拿到那个future凭证,就可以去干别的事情了(同时线程也在处理),等你真正要用到这个线程返回值的时候再通过future来获取,这样能缩短阻塞的时间。

    Demo

    接下来,我们看看Future的一个demo,这个例子很简单,就是为表明线程提交处理后,future对象是立即返回的,紧接着“Ready”马上就打印“Give the future”了;而当调用future.get的时候就停下了,“Get the future”迟迟没有打印,被阻塞了,直到线程执行完毕为止。这里我让他睡了3秒钟,能看得更清楚。

    public class FutureTest {
    	public static void main(String[] args) throws Exception {
            ExecutorService executor = Executors.newCachedThreadPool();
            System.out.println("Ready");
            Future strFuture = executor.submit(new TaskTest());
            System.out.println("Give the future");
            
            System.out.println("Get the future : " + strFuture.get());
            System.out.println("End");
            executor.shutdown();
        }
    
    	public static class TaskTest implements Callable {
    		@Override
    		public String call() throws Exception {
    			Thread.sleep(3000);
    			return "Hello World!";
    		}
    	}
    }
    

    Simulator

    从future的应用能看出来,其实future实现的功能很简单,就是充当一个线程返回结果的寄存器,只是在获取结果的时候,检查线程是否已完成,还在处理则阻塞,否则返回结果。
    下面我做了一个future的模拟实现:
    首先future作为一个结果寄存器,就需要有个result来存放结果,另外需要一个isFinish来标记线程是否完成。当然我在set()的时候不仅给result赋值,还把isFinish标记成完成,因为一般返回值都在线程结束时赋值的,所以我也这么简化设计了。
    测试使用上面的demo,运行结果也是一样的。只是我的这个future没有JDK那个优雅和健壮,那个还整合到ExecutorService,用起来更方便。
    所以,还有请大神们指导,这样的future实现,是不是还有什么漏洞?大笑

    public class FutureSimulator {
    	private volatile T result;
    	private volatile boolean isFinish = false;
    	public void set(T result) {
    		this.result = result;
    		this.isFinish = true;
    	}
    	public T get() throws InterruptedException {
    		while (!isFinish) {
    			Thread.sleep(100);
    		}
    		return result;
    	}
    	
        public static void main(String[] args) throws Exception {
        	   FutureSimulator future = new FutureSimulator();
            ExecutorService executor = Executors.newCachedThreadPool();
            System.out.println("Ready");
            executor.submit(new FutureTaskTest(future));
            System.out.println("Give the future");
    
            System.out.println("Get the future : " + future.get());
            System.out.println("End");
            executor.shutdown();
        }
    }
    
    class FutureTaskTest extends Thread {
    	private FutureSimulator future;
    	public FutureTaskTest(FutureSimulator future) {
    		this.future = future;
    	}
    
    	@Override
    	public void run(){
    		try {
    			Thread.sleep(3000);
    			future.set("Hello World!");
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }
    
  • 相关阅读:
    extern C的作用详解
    UIWindow in iOS
    iOS会议和组织
    Fantageek翻译系列之《使用Autolayout显示变化高度的UITableViewCell》
    KVO的概述的使用
    Struts2 基于XML校验(易百教程)
    Maven项目中添加JDBC驱动
    org.dom4j.DocumentException: null Nested exception: null解决方法
    struts2中的数据类型自动转换
    struts2的拦截器
  • 原文地址:https://www.cnblogs.com/pangblog/p/3324806.html
Copyright © 2020-2023  润新知