zoukankan      html  css  js  c++  java
  • Future设计模式

    Future设计模式

    示列引入

    在这里插入图片描述
    如上图,传统的订单下单流程,首先减商品库存,然后生成订单,然后生成订单详情,再通知短信等等,全部逻辑程序都是串行执行的.假如我们的系统特别'困难',减商品库存要1秒,生成订单要1秒,生成详情也要1秒,发送短信有可能要5秒,这里还不算查询商品的库存够不够下单等等,那么一系列的操作就要花很多时间。
    那么引入Future模式有什么好处呢?
    在这里插入图片描述
    future对象直接告诉你下单成功,返回给一个假数据,同时自己偷偷的建一个或者几个线程来处理业务逻辑,等业务逻辑处理完了,再返回一个正确的结果。

    示列代码

    /**
        返回数据接口
     */
    public interface Data {
        String getRequest();
    }
    
    /**
      RealData:真实数据,构造很慢的
     */
    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 getRequest() {
            return result;
        }
    }
    
    /**
      FutureData,当有线程想要获取RealData的时候,程序会被阻塞。等到RealData被注入才会使用getReal()方法
      FutureData:构造很快,但是是一个虚拟数据,需要装配
     */
    public class FutureData implements Data {
    
        protected RealData realData = null;
        protected boolean isReady = false;
        @Override
        public synchronized String getRequest() {
            while (!isReady) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    break;
                }
            }
            return realData.result;
        }
    
        public synchronized void setRealData(RealData realData) {
            if (isReady)
                return;
            this.realData = realData;
            isReady = true;
            notifyAll();
        }
    }
    
    /**
      Client:返回Data对象,立即返回FutureData,并开启线程装配RealData
     */
    public class Client {
        public Data request(String queryStr) {
            final FutureData futureData = new FutureData();
            new Thread(() -> {
                RealData realData = new RealData(queryStr);
                futureData.setRealData(realData);
            }).start();
            return futureData;
        }
    }
    
    public class Main {
        public static void main(String[] args) throws InterruptedException {
            Client client = new Client();
            //立即返回
            Data data = client.request("xxx");
            System.out.println("请求发送完毕。。。");
            //模拟客户端其他操作
            Thread.sleep(2000);
            //调用真实数据
            System.out.println(data.getRequest());
        }
    }
    

    总结

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

    Future模式JDK支持

    public interface Future<T> {
        T get() throws InterruptedException;
    }
    
    //返回的Future票据
    public class AsynFuture<T> implements Future<T> {
    
        private volatile boolean done = false;
        private T result;
        public void done(T result) {
            synchronized (this) {
                this.result = result;
                this.done = true;
                this.notifyAll();
            }
        }
        @Override
        public T get() throws InterruptedException {
            synchronized (this) {
                //这里不应该一直等待
                while (!done) {
                    this.wait();
                }
            }
            return result;
        }
    }
    
    /**
     *JDK中的FutureTask,public class FutureTask<V> implements RunnableFuture<V>
     其直接实现了Runnable接口,作为单独的线程启动,其中run()方法中,通过调用构造传递
     的Callable接口调用call()方法
     */
    public interface FutureTask<T> {
        T call();
    }
    
    public class FutureService {
        public <T> Future<T> submit(FutureTask task){
            AsynFuture<T> asynFuture = new AsynFuture<>();
            //开启线程直接处理,只是这里因为我们的FutureTask并没有继承Runnable接口,所以这里我们手动开启一个线程
            new Thread(() -> {
                T result = (T) task.call();
                asynFuture.done(result);
            }).start();
            return asynFuture;
        }
        //这是直接对处理结果进行处理,而不用返回Future
        public <T> void submit(FutureTask task, Consumer<T> consumer){
    //        AsynFuture<T> asynFuture = new AsynFuture<>();
            new Thread(() -> {
                T result = (T) task.call();
    //            asynFuture.done(result);
                consumer.accept(result);
            }).start();
    //        return asynFuture;
        }
    }
    
    public class SyncInvoker {
    
        public static void main(String[] args) throws InterruptedException {
    
            FutureService service = new FutureService();
            Future<String> future = service.submit(() -> {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "FINISH";
            });
    
            service.submit(() -> {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "FINISH";
            },System.out::println);
    
            System.out.println("=========================");
            System.out.println(" do other thing ");
            TimeUnit.SECONDS.sleep(1);
            System.out.println("==========================");
            System.out.println(future.get());
        }
    }
    

    参考博客

    高并发设计思想之Future模式:https://baijiahao.baidu.com/s?id=1614584183229617943&wfr=spider&for=pc

  • 相关阅读:
    聊一聊正则表达式,最全最常用总结
    11个优秀的Android开发开源项目
    一招教你打造一个滑动置顶的视觉特效
    这些优质的电子书 开发必备【干货精选】
    用Kotlin破解Android版微信小游戏跳一跳
    2017上半年技术文章集合【Android】—184篇文章分类汇总
    经常用到的字符串函数
    EhLib使用说明
    Delphi中本年、本月、本周的第一天和最后天
    Delphi中关于listview的一些使用
  • 原文地址:https://www.cnblogs.com/liuligang/p/10571390.html
Copyright © 2011-2022 走看看