在使用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()方法,则当前线程不会阻塞,接着执行后面的代码。
本文介绍如何通过Future接口实现异步方法,并演示了自定义Future实现类的过程,包括其核心方法cancel、isCancelled、isDone及get的实现。
954

被折叠的 条评论
为什么被折叠?



