欢迎微信搜索并关注“小猴子的技术笔记”公众号 私信我 领取丰富的视频学习资料!
开发业务中有不少用到线程的场景。遇到比较耗时的场景每每会起一个线程进行执行,若是不返回结果就能够直接new一个Thread对业务进行操做。由于runnable不会返回结果,也不会抛出异常,若是须要拿到返回值的话则须要使用Callable和Future或者Future Task进行结合。java
这里能够简单理解为“Callable”表示产生结果和抛出异常。而“Future”是一个接口,表示异步计算结果微信
“Callable”是一个泛型接口,里面只有一个方法“call()”能够用来计算产生结果,若是没法执行就抛出异常。异步
@FunctionalInterface public interface Callable<V> { // 结算结果。若是没法执行则抛出异常 V call() throws Exception; }
“Future”也是一个泛型接口用来获取异步计算的结果,经过查看源码能够了解到“Future”为咱们提供了如下的几个方法:ide
public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
“boolean cancel(boolean mayInterruptedRunning)”:尝试取消执行此任务,若是任务已经完成,则调用返回false。若是任务已经启动,而且“mayInterruptedRunning”设置为true,那么将以中断执行此任务线程的方式来试图中止任务,成功返回true,失败返回false。学习
“boolean isCancelled()”:若是任务完成前被取消则返回true。测试
“boolean isDone()”:不管是任务正常结束仍是中途被中断或者因为其余缘由而结束,都将返回true。this
“V get()”:获取计算结果,若是计算尚未完成就调用了这个方法那么线程将会阻塞等待获取计算完成。spa
“V get(long timeout, TimeUnit unit)”:获取计算结果,若是计算尚未完成就调用了这个方法,那么线程将会等待设置的时间内会抛出异常。若是在获取等待的过程当中遇到了线程的中断、取消、线程池等异常也是会被捕获到。线程
由于Future是一个接口,没有办法被实例化,所以须要使用FutureTask进行类的建立。code
public class FutureTask<V> implements RunnableFuture<V> { // 省略了一下方法 }
public interface RunnableFuture<V> extends Runnable, Future<V> { void run(); }
先看一个Callable和Future结合运行的例子:
public class MyCallable implements Callable<String> { private int sleepTime; private String msg; public MyCallable(int sleepTime, String msg) { this.sleepTime = sleepTime; this.msg = msg; } @Override public String call() throws Exception { TimeUnit.SECONDS.sleep(sleepTime); System.out.println("线程休眠了:" + sleepTime + "秒执行完毕"); return msg; } }
而后进行测试,测试代码以下:
public class FutureTest { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executor = Executors.newCachedThreadPool(); System.out.println("~~~~~~~~~~~~~开始进行业务的计算~~~~~~~~~~~~~~"); Future<String> first = executor.submit(new MyCallable(3, "hello!")); Future<String> second = executor.submit(new MyCallable(2, "可爱的小猴子,要加油哦!")); // 主线程能够继续执行一些其余的任务 System.out.println("~~~~~~~主线程能够继续执行一些其余的任务~~~~~~~"); System.out.println("最后的结果:" + first.get() + " " + second.get()); executor.shutdown(); } }
最后的运行结果:
~~~~~~~~~~~~~开始进行业务的计算~~~~~~~~~~~~~~ ~~~~~~~主线程能够继续执行一些其余的任务~~~~~~~ 线程休眠了:2秒执行完毕 线程休眠了:3秒执行完毕 最后的结果:hello!可爱的小猴子,要加油哦!
若是使用FutureTask的话,则代码的示例以下:
public class FutureTaskTest { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executor = Executors.newCachedThreadPool(); System.out.println("~~~~~~~future task 开始进行业务的计算~~~~~~~~~"); FutureTask<String> first = new FutureTask<>(new MyCallable(2, "加油!")); FutureTask<String> second = new FutureTask<>(new MyCallable(5, "努力的人儿!")); executor.submit(first); executor.submit(second); executor.shutdown(); System.out.println("~~~~~~~主线程能够继续执行一些其余的任务~~~~~~~"); System.out.println("最后的结果:" + first.get() + " " + second.get()); } }
运行结果:
~~~~~~~future task 开始进行业务的计算~~~~~~~~~ ~~~~~~~主线程能够继续执行一些其余的任务~~~~~~~ 线程休眠了:2秒执行完毕 线程休眠了:5秒执行完毕 最后的结果:加油!努力的人儿!
欢迎微信搜索并关注“小猴子的技术笔记”公众号 私信我 领取丰富的视频学习资料!