- 我们之前使用的多线程需要在run方法中执行多线程代码,但是run方法有一个致命缺点,就是他的返回值是空。但是,如果我们像要我们如何知道子线程执行完毕呢?没有返回值告诉我们,所以我们需要上面的两种模式。
Callable模式
其实,Callable就相当于一个有返回值的线程,而Future是一个可以接收Callable的返回值。
Callable的源代码如下:
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
他和Runable接口源代码是很相似的。他和Runable的唯一的不同是返回值V是泛型,而Runable是void.
Future常用方法
V get() :获取异步执行的结果,如果没有结果可用,此方法会阻塞直到异步计算完成。
V get(Long timeout , TimeUnit unit) :获取异步执行结果,如果没有结果可用,此方法会阻塞,但是会有时间限制,如果阻塞时间超过设定的timeout时间,该方法将抛出异常。
boolean isDone() :如果任务执行结束,无论是正常结束或是中途取消还是发生异常,都返回true。
boolean isCanceller() :如果任务完成前被取消,则返回true。
boolean cancel(boolean mayInterruptRunning) :如果任务还没开始,执行cancel(...)方法将返回false;如果任务已经启动,执行cancel(true)方法将以中断执行此任务线程的方式来试图停止任务,如果停止成功,返回true;当任务已经启动,执行cancel(false)方法将不会对正在执行的任务线程产生影响(让线程正常执行到完成),此时返回false;当任务已经完成,执行cancel(...)方法将返回false。mayInterruptRunning参数表示是否中断执行中的线程。
通过方法分析我们也知道实际上Future提供了3种功能:(1)能够中断执行中的任务(2)判断任务是否执行完成(3)获取任务执行完成后额结果。
实例:
public class TestMain {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newCachedThreadPool();
Future<Integer> future = executor.submit(new AddNumberTask());
System.out.println(Thread.currentThread().getName() + "线程执行其他任务");
Integer integer = future.get();
System.out.println(integer);
// 关闭线程池
if (executor != null)
executor.shutdown();
}
}
class AddNumberTask implements Callable<Integer> {
public AddNumberTask() {
}
@Override
public Integer call() throws Exception {
System.out.println("####AddNumberTask###call()");
Thread.sleep(5000);
return 5000;
}
}
Future的好处就是先传给你一个结果,然后等资源全部解析完成之后,再传给你值,相当于ajax的异步.
手写Callable
仔细一想,这相当于生产者消费者模型。可以用wait和notify来解决。
核心代码:
package com.Future;
/**
* Created with IntelliJ IDEA.
* User: WHOAMI
* Time: 2019-2019/4/21-13:00
* Description: :/TODO_
*/
public class FutureCore {
//请求参数
private String arg;
//标识变量
private volatile boolean FLAG = false;
//返回结果
private String result;
public FutureCore(String arg) {
this.arg = arg;
}
//这里可能会有阻塞,模拟下载
public synchronized void setRequest(){
if(FLAG){
return;
}
System.out.println("接收网络参数" + arg+";数据请求中...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.result = "结果";
FLAG = true;
notify();
}
//返回结果
public synchronized String getResult(){
while (!FLAG){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return result;
}
}
这里是封装future的类
package com.Future;
/**
* Created with IntelliJ IDEA.
* User: WHOAMI
* Time: 2019-2019/4/21-13:05
* Description: :/TODO_
*/
public class FutureUtil {
public static FutureCore submit(String arg){
FutureCore futureCore = new FutureCore(arg);
//子线程开始下载资源
new Thread(new Runnable() {
@Override
public void run() {
futureCore.setRequest();
}
}).start();
//直接返回结果
return futureCore;
}
}
测试主函数如下:
package com.Future;
/**
* Created with IntelliJ IDEA.
* User: WHOAMI
* Time: 2019-2019/4/21-13:09
* Description: :/TODO_
*/
public class ThreadTest {
public static void main(String args[]){
System.out.println("开始future");
FutureCore core = FutureUtil.submit("测试");
System.out.println("主线程继续执行");
System.out.println(core.getResult());
}
}
结果如下: