Future实现一个简单的异步功能

本文介绍如何通过Future接口实现异步方法,并演示了自定义Future实现类的过程,包括其核心方法cancel、isCancelled、isDone及get的实现。

在使用ThreadPoolExecutor构建线程池的时候我们可以通过调用submit()方法得到一个Future的结果,这样就实现了一个异步调用方法的功能了,现在我们自己试着来实现一个简单的异步方法

1、首先来看一下Future这个接口里面有哪些内容

里面比较重点的有get()和get(long,TimeUnit)这个两个方法,这两个方法也就是我们异步得到执行结果的关键点咯

2、编写具体的实例

public class FutureTest {
    volatile boolean  isDone=false;  //表示当前任务是否已执行完
    volatile boolean isCancel=false;  //表示当前任务是否已经取消了
    String value=null;  //最终任务返回的结果
    ReentrantLock lock=new ReentrantLock();
    volatile Condition condition=null;
    public  Future<String> asyncGetName(){
        Future<String> result=new Future<String>() {
            @Override
            public boolean cancel(boolean mayInterruptIfRunning) {
                return isCancel;
            }

            @Override
            public boolean isCancelled() {
                return isCancel;
            }

            @Override
            public boolean isDone() {
                return isDone;
            }

            @Override
            public String get() throws InterruptedException, ExecutionException {
                int i=0;
                while (!isDone && i<100){  //这里简单的实现一个自旋锁的功能 这里实现100次自选
                    i++;
                }
                if(!isDone){  //如果自旋锁自选了100次之后任务还没执行完就将当前线程阻塞起来
                    try {
                        lock.lock();  //先获取锁 如果没有获取到就阻塞
                        if(!isDone) { //如果已经获取到了锁 而任务还没执行完那就放弃获取到的锁并且进入等待状态
                            condition = lock.newCondition();
                            condition.await();
                        }
                    }finally {
                        lock.unlock();
                    }
                }
                return value;
            }

            @Override
            public String get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
                //实现方式和上面的一样,不过要多加一个等待时间 这里就不加了
                return value;
            }
        };
        Thread thread=new Thread(()->{  //模拟当前任务耗时10秒钟
            try {
                System.out.println("子线程已经开始了===="+Thread.currentThread().getId()+"==="+LocalDateTime.now());
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程休眠完了===="+Thread.currentThread().getId()+"==="+LocalDateTime.now());
            isDone=true;
            value="abc";  //当前任务模拟消耗时间用完之后就返回结果
            try {  //如果前面调用获取结果的线程被阻塞了那就唤起线程
                lock.lock();
                if(condition!=null) {
                    condition.signalAll();
                }
            }finally {
                lock.unlock(); //释放锁
            }
        });
        thread.start();
        return result;
    }
}

3、编写测试用例

a、先不取执行结果

FutureTest futureTest=new FutureTest();
        System.out.println("查询结果:=="+Thread.currentThread().getId()+"==="+ LocalDateTime.now());
        Future<String> result= futureTest.asyncGetName();
//        try {
//            System.out.println("结果:"+result.get());
//        } catch (ExecutionException e) {
//            e.printStackTrace();
//        }
        System.out.println("end==="+Thread.currentThread().getId()+"==="+LocalDateTime.now());

执行结果

b、取执行结果

FutureTest futureTest=new FutureTest();
System.out.println("查询结果:=="+Thread.currentThread().getId()+"==="+ LocalDateTime.now());
Future<String> result= futureTest.asyncGetName();
try {
    System.out.println("结果:"+result.get());
} catch (ExecutionException e) {
    e.printStackTrace();
}
System.out.println("end==="+Thread.currentThread().getId()+"==="+LocalDateTime.now());

对比两个结果可以看出当对Future对象调用get()方法的时候,如果任务没有执行完当前线程就会阻塞,而如果不调用get()方法,则当前线程不会阻塞,接着执行后面的代码。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值