【详解】Java并发之Fature设计模式

分析

  • Future模式的核心在于:去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑。

  • Future模式有点类似于商品订单。在网上购物时,提交订单后,在收货的这段时间里无需一直在家里等候,可以先干别的事情。类推到程序设计中时,当提交请求时,期望得到答复时,如果这个答复可能很慢。传统的是一直持续等待直到这个答复收到之后再去做别的事情,但如果利用Future模式,其调用方式改为异步,而原先等待返回的时间段,在主调用函数中,则可以用于处理其他事务。

总结来说就是在调用一个很复杂的函数时,不需要等待其完成,而是采用异步的方式执行其他的代码

一个同步的例子

public class SyncInvoker {


    public static void main(String[] args) throws InterruptedException {
        //get方法的阻塞导致了主函数的阻塞
        String result = get();
        System.out.println(result);
    }

    private static String get() throws InterruptedException {

        //模拟一个很耗时的操作
        Thread.sleep(10_000);
        return "FinISH";
    }
}
  • 执行的get操作会阻塞住主线程的工作

Future模式

先设计一个接口,代表未来的凭据,相当于发票

/**
 * 获取结果
 * Furture 代表未来的凭据,相当于买的火车票
 * @param <T>
 */
public interface Furture<T> {

    T get() throws InterruptedException;

}

实现Future接口
有两个方法

  • 一个方法交给其他线程在完成任务后,将结果放入到结果集
  • 一个方法负责提取结果集的数据,如果此时没用做完,就陷入阻塞
/**
 * 一个Future的实现类
 * 有两个方法
 * 一个方法交给其他线程在完成任务后,将结果放入到结果集
 * 一个方法负责提取结果集的数据,如果此时没用做完,就陷入阻塞
 * @param <T>
 */
public class AsynFuture<T> implements Future<T> {

    private volatile boolean done = false;

    private T result;

    /**
     * 当完成工作后,负责写入数据
     * @param result
     */
    public void done(T result){
        synchronized (this){
            this.result = result;
            this.done = true;
            this.notifyAll();
        }
    }


    /**
     * 判断是否完成,如果完成,将结果返回
     * 如果没有,陷入阻塞
     * @return
     * @throws InterruptedException
     */
    @Override
    public T get() throws InterruptedException {
        synchronized (this){
            while (!done){
                this.wait();
            }
        }
        return result;
    }
}

设计一个桥梁桥接Future和FutureTask
主要思想是:

  • 设计一个线程执行FutureTask的任务,在执行完成后,放到asynFuture的结果集中
  • 返回asynFuture的结果集,供主方法自由的调用
/**
 * 桥接Future和FutureTask
 */
public class FutureService {

    public <T> Future<T> submit(FutureTask<T> task) {

        AsynFuture<T> asynFuture = new AsynFuture<>();

        //创建一个线程专门负责执行任务
        new Thread(()->{
            T result = task.call();
            asynFuture.done(result);
        }).start();

        return asynFuture;
    }

    public <T> void submit(FutureTask<T> task, Consumer<T> consumer) {

        AsynFuture<T> asynFuture = new AsynFuture<>();

        //创建一个线程专门负责执行任务
        new Thread(()->{
            T result = task.call();
            asynFuture.done(result);
            consumer.accept(result);
        }).start();
    }
}

测试

public class AsynClient {
    public static void main(String[] args) throws InterruptedException {
        FutureService futrueService = new FutureService();

        Future<String> future = futrueService.submit(() -> {
            try {
                Thread.sleep(5_000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "FINISH";
        });
        System.out.println("我先去忙啦");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("我看看你完成没有");

        System.out.println(future.get());

//        futrueService.submit(()->{
//            try {
//                Thread.sleep(3_000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            return "FINISH";
//        },System.out::println);
//        System.out.println("我先去忙啦");

    }
}

结果:

我先去忙啦
我看看你完成没有
FINISH

  • 可以看到代码并没有因为任务的执行而陷入阻塞
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值