当前位置:网站首页>JUC框架 从Runnable到Callable到FutureTask 使用浅析
JUC框架 从Runnable到Callable到FutureTask 使用浅析
2022-07-27 10:57:00 【anlian523】
前言
本文旨在简单讲解Runnable、Callable、FutureTask这几个线程执行相关的接口和类。为后面FutureTask源码讲解作铺垫。
Runnable
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
我们知道创建线程有两种方式:
- override掉
Thread的run方法:
new Thread() {
@Override
public void run() {
int count = 0;
for(int i = 1;i <= 100;i++)
count += i;
}
}.start();
看过Thread源码都知道,我们调用Thread#start()后,会创建一个新线程来执行这个Thread的run方法。但上面这种执行者和执行task绑定在一起了,不灵活。
- 传递一个
Runnable对象给Thread:
new Thread(new Runnable(){
@Override
public void run() {
int count = 0;
for(int i = 1;i <= 100;i++)
count += i;
}
}).start();
这样,通过创建一个Runnable匿名内部类对象,可以达到同样的效果,但是却把执行者和执行task分开了。
public class Thread implements Runnable {
/* What will be run. */
private Runnable target;
@Override
public void run() {
if (target != null) {
target.run();
}
}
}
从Thread源码可以看到,当没有override掉run方法时,run方法将执行持有的Runnable对象的run方法。简单的说,就是套娃。
public class test5 {
public static Runnable task = new Runnable() {
@Override
public void run() {
int count = 0;
for(int i = 1;i <= 100;i++)
count += i;
}
};
public static void main(String[] args) throws InterruptedException {
new Thread(task).start();
new Thread(task).start();
}
}
将执行者和执行task分开是有好处,上例就体现了两个执行者可以执行同一个task。
Callable
与Runnable相比,Callable接口有些不同之处:
- Runnable接口没有返回值,Callable接口有返回值。又因为是返回值是泛型,所以任何类型的返回值都支持。
- Runnable接口的run方法没有
throws Exception。这意味着,Runnable不能抛出异常(子类不能抛出比父类更多的异常,但现在Runnable的run方法本身没有抛出任何异常);Callable接口可以抛出异常。
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
但注意,Thread并没有一个构造器可以接受Callable参数的,而且Thread也没有一个Callable类型成员的。
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
看来要想使用Callable还得依靠别的东西。
FutureTask
先回答上面的问题,要想使用Callable还得依靠FutureTask,虽然这里暂且看不出来FutureTask和Callable的关系。
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
原来是FutureTask的构造器可以接受一个Callable对象,这就把这二者串起来了,而FutureTask本身又是一个Runnable,这说明可以把FutureTask传递给Thread对象的构造器。
public class test5 {
public static void main(String[] args) throws InterruptedException {
FutureTask<Integer> result = new FutureTask<Integer>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int count = 0;
for(int i = 1;i <= 100;i++)
count += i;
return count;
}
});
new Thread(result).start();
try {
System.out.println(result.get());
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
/*output: 5050 */
上面例子给出了FutureTask的用法,看起来是线程通过FutureTask对象间接调用到了Callable的call方法。注意,调用result.get()时主线程会阻塞一会直到call方法执行完毕。
别看这个类图稍微复杂,其实RunnableFuture就是将Future和Runnable合成一个新接口而已,但没有增加任何一个新方法。Runnable我们已经看过了,看看Future吧:
public interface Future<V> {
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
}
Future被设计为一个可以异步获得task执行结果的接口。
get()。获得task执行结果,如果task已经执行完,马上返回执行结果;如果task未执行完毕,则阻塞直到执行完毕。get(long timeout, TimeUnit unit)。上一个函数的超时版本,阻塞直到 执行完毕或超时。cancel(boolean mayInterruptIfRunning)。尝试取消task,返回值代表取消操作成功。isCancelled()。判断一个task已经被取消了。取消一定是task没有执行完毕前就被取消,也包括根本没有执行就被取消。isDone()。如果一个任务已经结束, 则返回true。返回true有三种情况:normal termination。正常执行完毕。an exception。执行过程抛出异常。cancellation。task被取消。
当然,一般我们是配合线程池来使用Callable:
package com.xxx.future;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class BlockingTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
final ExecutorService service = Executors.newFixedThreadPool(5);
Future<String> result = service.submit(new Callable<String>() {
@Override
public String call() throws Exception {
//模拟现实中的异步过程,等待五秒返回结果
Thread.sleep(1000*5);
return "ok";
}
});
System.out.println("task begin...");
//如果线程没有执行完成,那么继续等待,通过打印信息来直观感受线程执行过程
while(!result.isDone()){
System.out.println("wait for 1 second");
Thread.sleep(1000);
}
String ok = result.get();
service.shutdown();
System.out.println("task end "+ok);
}
}
但其实线程池的做法也是构造一个FutureTask。
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
边栏推荐
- Moveit2 - 1. Start
- zabbix自定义监控项
- Digital triangle model acwing 275. pass note
- Pat (Grade B) 2022 summer exam
- Moveit2 - 5. Scenario Planning
- 【着色器实现Shake随机摇动效果_Shader效果第十篇】
- Digital triangle model acwing 1018. Minimum toll
- 局域网SDN技术硬核内幕 12 云网CP的日常恩爱——硬件VXLAN转发平面
- Maker Hongmeng application development training notes 02
- Why choose smart TV?
猜你喜欢

最长上升子序列模型 AcWing 1010. 拦截导弹

Knapsack model acwing 1024. Packing problem

Longest ascending subsequence model acwing 272. longest common ascending subsequence

Analysis of distributed database and cache double write consistency scheme (Reprint)

Gaussian elimination acwing 883. solving linear equations with Gaussian elimination

力扣——10. 正则表达式匹配

Knapsack problem acwing 9. grouping knapsack problem

82. (cesium home) cesium points move on 3D models

【Unity入门计划】CreatorKitFPS:第一人称射击3D小游戏

最长上升子序列模型 AcWing 1017. 怪盗基德的滑翔翼
随机推荐
Caused by:org.gradle.api.internal. plugins . PluginApplicationException: Failed to apply plugin
Error while unzipping file in win10: unable to create symbolic link. You may need to run WinRAR with administrator privileges. The client does not have the required privileges
C# 自定义集合
求组合数 AcWing 888. 求组合数 IV
(8) Shell function
WGet warning: unable to verify
Markdown editor syntax - setting of text color, size, font and background color (Reprint)
349 sum of intersection of two arrays and 01
Find the combination number acwing 885. find the combination number I
Maker harmony OS application development training notes 01
第13章 IO流
Caused by:org.gradle.api.internal.plugins . PluginApplicationException: Failed to apply plugin
第10章 枚举类与注解
Maker Hongmeng application development training 04
Gaussian elimination acwing 884. Gaussian elimination for solving XOR linear equations
Quantitative industry knowledge summary
最长上升子序列模型 AcWing 482. 合唱队形
多种进制之间的转换
Backpack model acwing 1022. Collection of pet elves
2022 Niuke multi school training (3) a-ancestor topic translation