Callable是类似Thread和Runnable,也是一种创建线程的方式,只不过Callable创建的线程可以带返回值。
可以看下Callable的源码如下:
@FunctionalInterface
public interface Callable {
/**
* 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;
}
可以看到它的返回值就是传入的V值
使用方法如下:
static class TestA implements Callable {
@Override
public String call() throws Exception {
return "我是一个带返回值的线程";
}
}
这里先不说怎么调用它,放在下面讲Future和FutureTask的时候一起说
Future是对具体的线程的执行结果进行取消、查询是否完成、获取结果。
如Runnable、Callable线程。
我们可以看下Future的源码,注释部分我给删除了,想看的自行看源码去
public interface Future {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
cancel(boolean mayInterruptRunning) 方法
1.用来取消线程,如果取消成功则返回true,取消失败则返回false。
2.mayInterruptIfRunning参数是否允许取消正在执行却没有执行完毕的任务。
3.如果任务已经完成无论mayInterruptIfRunning设置的是true还是false,都返回false。
4.取消进行中任务mayInterruptIfRunning设置为true 返回true。
5.取消进行中任务mayInterruptIfRunning设置为false返回false。
6.如果任务还未执行不管mayInterruptIfRunning设置的是true还是false,都返回true。
isCancelled方法
1.判断当前任务是否取消成功,如果在任务正常完成前被取消成功,则返回 true。
isDone方法
1.表示任务是否已经完成,若任务完成,则返回true。
get方法
1.用来获取任务执行结果,这个方法会产生阻塞,会等到任务完成后才会返回,慎用。
2.相当于ABC三行代码,A是线程任务,B是get方法获取该线程返回值,如果A线程一直没有完成,B这里会一直阻塞,导致C没法执行。
get(long timeout, TimeUnit unit)方法
1.跟上面的get方法一样都是获取任务执行结果,只不过这个可以设置超时时间,超过时间没有返回直接返回null
总结Future有三个功能:判断任务是否完成,取消任务,获取任务结果。
下面是实战代码:
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("主线程开始执行");
TestA a = new TestA();
// 这里说一下一般Callable都是配合线程池一起使用,这里是手动new了一个newCachedThreadPool()的无参数线程池
// 不懂的的可以自行百度线程池使用方式
ExecutorService executorService = Executors.newCachedThreadPool();
Future executors = executorService.submit(a);
// get方法
System.out.println(executors.get());
// 判断线程是否完成
System.out.println(executors.isDone());
// 关闭线程池
executorService.shutdown();
System.out.println("主线程执行完成");
}
static class TestA implements Callable {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "我是一个带返回值的线程";
}
}
返回结果如下:
主线程开始执行
我是一个带返回值的线程
true
主线程执行完成
我们先看下FutureTask源码
public class FutureTask implements RunnableFuture
public interface RunnableFuture extends Runnable, Future
1.它是实现了RunnableFuture接口,然后RunnableFuture继承了Runnable和Future
2.所以TutureTask可以作为Runnable被执行,也能作为Future得到Callable的返回值
3.RunnableFuture提供了2个构造器我也是从源码复制出来的,如下:
public FutureTask(Callable callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
4.它里面也提供了一系列跟Future一样的get、isDone等的方法。
5.FutureTask用法,直接看代码吧
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("主线程开始执行");
// 这里还是用下线程池
ExecutorService executorService = Executors.newCachedThreadPool();
TestA a = new TestA();
FutureTask task = new FutureTask(a);
executorService.submit(task);
// 把FutureTask当成Runnable去执行,这个实现方式是跟上面一样的,只不过用的是Thread
/*Thread thread = new Thread(task);
thread.start();*/
// get方法
System.out.println(task.get());
// 判断线程是否完成
System.out.println(task.isDone());
// 关闭线程池
executorService.shutdown();
//这里在提一下上面submit是有返回值的,这里就不多说有兴趣的可以自己去看
System.out.println("主线程执行完成");
}
static class TestA implements Callable {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "我是一个带返回值的线程2";
}
}
运行结果如下:
主线程开始执行
我是一个带返回值的线程2
true
主线程执行完成
好了到这里Callable、Future、FutureTask也介绍完了,看完的你应该也掌握了基本的用法了,如哪里讲的不好还望指出,喜欢的可以关注作者。