Callable
创建线程有四种方式:
- 继承Thread类
- 实现Runnable接口
- Callable接口
- 线程池
前两种前面说过了, Runnable接口是比较常用的, 因为在Java中继承是很重要的, 不能随便使用, 但是Runnable接口有一个缺点, run()方法没有返回值, 也就是当线程结束时, 不能返回结果, 为了能返回结果, 在JDK1.5以后出现了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;
}
Callable接口中的call()方法可以用来处理任务并返回一个结果, 如果无法处理, 则会抛出异常。
Runnable和Callable的区别:
- Callable规定的方法是call(), Runnable规定的方法是run()
- Callable的任务执行后可返回值, 而Runnable的任务是不能返回值
- call()方法可以抛出异常, run()方法不能
下面就写一个简单的类实现Callable接口:
//返回一个10以内的随机数
class GetNumber implements Callable<Integer> {
@Override
public Integer call() throws Exception {
return new Random().nextInt(10);
}
}
但是当我们想要去创建这样一个线程去测试的时候发现, Thread的构造方法里没有一个是需要传入Callable接口的, 只能传入Runnable接口, 那么有什么方法可以让Callable接口转成Runnable接口呢?
FutureTask
先来看一下FutureTask的继承结构
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-srzBASld-1650026154305)(/img/2022-04-06/01.png)]](https://i-blog.csdnimg.cn/blog_migrate/abec9799aca6ee15c5b6727aaaff1fd2.png)
FutureTask是Runnable的一个实现类, 再来看一下FutureTask的构造方法
/**
* Creates a {@code FutureTask} that will, upon running, execute the
* given {@code Callable}.
*
* @param callable the callable task
* @throws NullPointerException if the callable is null
*/
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
需要传入一个Callable接口, 那么使用FutureTask就可以将Callable接口转成Runnable接口了
再来看一下FutureTask的另一个构造方法
/**
* Creates a {@code FutureTask} that will, upon running, execute the
* given {@code Runnable}, and arrange that {@code get} will return the
* given result on successful completion.
*
* @param runnable the runnable task
* @param result the result to return on successful completion. If
* you don't need a particular result, consider using
* constructions of the form:
* {@code Future<?> f = new FutureTask<Void>(runnable, null)}
* @throws NullPointerException if the runnable is null
*/
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
创建一个FutureTask将在运行, 执行给定Runnable, 安排get()将返回给定的成功完成。
最后看一下FutureTask的常用方法
get(), 如果有必要等待计算完成, 然后获取它的结果isDone(), 如果正常终止, 或是发生异常, 或是手动取消, 返回true
使用FutureTask来完成我们的案例
public class CallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//普通创建
FutureTask<Integer> integerFutureTask1 = new FutureTask<>(new GetNumber());
//Lambda表达式创建
FutureTask<Integer> integerFutureTask2 = new FutureTask<>(() -> {
System.out.println(Thread.currentThread().getName() + " come in callable!");
//返回一个10以内的随机数
return new Random().nextInt(10);
});
//创建线程
new Thread(integerFutureTask1, "tom").start();
new Thread(integerFutureTask2, "jerry").start();
//打印结果
System.out.println("tom get " + integerFutureTask1.get());
System.out.println("jerry get " + integerFutureTask2.get());
//主线程结束
System.out.println(Thread.currentThread().getName() + " over!");
}
}
class GetNumber implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + " come in callable!");
//返回一个10以内的随机数
return new Random().nextInt(10);
}
}
查看运行结果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d6OCOpIi-1650026154307)(/img/2022-04-06/02.png)]](https://i-blog.csdnimg.cn/blog_migrate/42305dcb74cb64b500cada3b347e94f2.png)
运行成功!
我的个人主页: www.ayu.link
本文连接: ┏ (゜ω゜)=☞
本文介绍了Java中创建线程的四种方式,重点关注Callable接口和FutureTask的使用。Callable接口允许任务有返回值,而FutureTask可以将Callable转换为Runnable,方便线程执行。通过实例展示了如何创建Callable任务,并使用FutureTask来获取任务结果。最后,通过FutureTask的get()方法获取线程执行后的结果。
689

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



