黄沙百战穿金甲,不破楼兰终不还。这篇文章主要讲述Android进阶——多线程系列之ThreadRunnableCallableFutureFutureTask相关的知识,希望能为你提供帮助。
前言 多线程一直是初学者最抵触的东西,
如果你想进阶的话,
那必须闯过这道难关,
特别是多线程中Thread、Runnable、Callable、Future、FutureTask这几个类往往是初学者容易搞混的。这里先总结这几个类特点和区别,
让大家带着模糊印象来学习这篇文章
- Thread、Runnable、Callable: 都是线程
- Thread特点: 提供了线程等待、线程睡眠、线程礼让等操作
- Runnable和Callable特点: 都是接口, 并提供对应的实现方法
- Runnable、Callable区别: Runnable无返回值, Callable有返回值
- Future: 提供了对Runnable和Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果等操作
- FutureTask: Runnable和Future的结合体, 即拥有Future的特性
new Thread(new Runnable() {
@
Override
public void run() {
//子线程操作
}
}).start();
new Thread(){
@
Override
public void run() {
//子线程操作
}
}.start();
这也就是我们要讲的Thread和Runnable的关系, 其实它们是一样的, 都是线程, 最终启动线程后都会执行run()方法里面的内容, 具体是怎么一回事, 让我们从Thread的源码开始分析
class Thread implements Runnable {private Runnable target;
//构造函数
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "
Thread-"
+
nextThreadNum(), 0);
}//继续追踪init()方法
private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
Thread parent =
currentThread();
if (g =
=
null) {
g =
parent.getThreadGroup();
}g.addUnstarted();
this.group =
g;
this.target =
target;
this.priority =
parent.getPriority();
this.daemon =
parent.isDaemon();
setName(name);
init2(parent);
/* Stash the specified stack size in case the VM cares */
this.stackSize =
stackSize;
tid =
nextThreadID();
}}
可以看到Thread就是实现Runnable的, 所以Thread也可以说是Runnable, 它俩就像亲生兄弟一样。由于我们创建线程的时候第一步都是new Thread()开始的, 所以看到Thread的构造函数, 继续追踪之后, 你会发现如果传进来一个Runnable的话, 会被赋予target的成员变量中, 而target就是一个Runnable。接着, 调用Thread的start()方法, 我们查看start()方法的源码
public synchronized void start() {
if (threadStatus !=
0)
throw new IllegalThreadStateException();
group.add(this);
started =
false;
try {
//最终调用这个方法
nativeCreate(this, stackSize, daemon);
started =
true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {}
}
}//继续追踪nativeCreate()方法
private native static void nativeCreate(Thread t, long stackSize, boolean daemon);
我们可以看到start()方法在最后是调用了本地底层的nativeCreate()方法, 这个方法我们大胆的猜测, 应该是执行Thread里面的run()方法, 因为我们开启线程之后, 线程总是会执行run()里面的内容, 所以这里应该就是调用了Thread的run()方法。我们查看run()方法的源码
@
Override
public void run() {
if (target !=
null) {
target.run();
}
}
到这里, 实际上最终被线程执行的任务是Runnable而非Thread, Thread只是对Runnable的包装。如果target不为空则执行target的run()方法, 否则执行当前对象的run()方法
Runnable和Callable的区别 Runnable和Callable同样都是线程, 而它们的区别可以从其源码中看出来, 下面是Runnable和Callable的源码
public interface Runnable {public abstract void run();
}@
FunctionalInterface
public interface Callable<
V>
{V call() throws Exception;
}
可以发现, Callable带有一个泛型的返回值, 而Runnable并没有返回值, 所以使用Callable可以返回线程的结果, 而Runnable不行
Future Future不是线程, 它可以理解为管理线程的人, 不过它对线程的管理方法不是很多, 这点可以从Future的源码中看出来, 下面是Future的源码
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;
}
关说不练假把式, 我们通过例子来理解, 这里的线程我们都使用线程池来执行, 如果对线程池不理解的, 可以查看我的博客Android进阶——多线程系列之四大线程池的使用介绍
public class ThreadActivity extends AppCompatActivity {@
Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread);
//线程池
ExecutorService executor =
Executors.newFixedThreadPool(10);
//第一步:
创建线程
MyRunnable myRunnable =
new MyRunnable();
MyCallable myCallable =
new MyCallable();
try {
//第二步:
执行线程带有返回值
Future<
Integer>
CallableFuture =
executor.submit(myCallable);
//get()方法会使线程阻塞
System.out.println("
CallableFuture获取的结果:
"
+
CallableFuture.get());
System.out.println("
CallableFuture isCancelled(
是否已经取消)
:"
+
CallableFuture.isCancelled());
System.out.println("
CallableFuture isDone(
是否已经完成)
:"
+
CallableFuture.isDone());
//第二步:
执行线程没有返回值
Future<
?>
RunnableFuture =
executor.submit(myRunnable);
System.out.println("
RunnableFuture获取的结果:
"
+
RunnableFuture.get());
System.out.println("
RunnableFuture isCancelled(
是否已经取消)
:"
+
RunnableFuture.isCancelled());
System.out.println("
RunnableFuture isDone(
是否已经完成)
:"
+
RunnableFuture.isDone());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}public class MyRunnable implements Runnable {
@
Override
public void run() {
System.out.println("
我是Runnable"
);
}
}public class MyCallable implements Callable<
Integer>
{
@
Override
public Integer call() throws Exception {
System.out.println("
我是Callable"
);
return 10;
}
}
}
第一步: 创建线程MyCallable中是实现Callable的, 泛型里面填返回值的类型, 而Runnable则不用
第二步: 通过线程池executor提交线程, 返回对应的Future< ?> 对象, 若有返回值则填返回值类型, 若无返回值则填? 号
下面我们通过打印信息来查看Future管理类的执行结果, 再一次的证明: Runnable和Callable的区别
我是Callable
CallableFuture获取的结果:
10
CallableFuture isCancelled(
是否已经取消)
:false
CallableFutureisDone(
是否已经完成)
:true
我是Runnable
RunnableFuture获取的结果:
null
RunnableFuture isCancelled(
是否已经取消)
:false
RunnableFuture isDone(
是否已经完成)
:true
FutureTask FutureTask是Future的实现类, 而且不仅是Future又是Runnable, 还包装了Callable, 它是这两者的合体。从FutureTask的源码可以看出
//继续追踪RunnableFuture
public class FutureTask<
V>
implements RunnableFuture<
V>
{
//构造方法
public FutureTask(Callable<
V>
callable) {
if (callable =
=
null)
throw new NullPointerException();
this.callable =
callable;
this.state =
NEW;
}
//构造方法
public FutureTask(Runnable runnable, V result) {
this.callable =
Executors.callable(runnable, result);
this.state =
NEW;
}
}
//RunnableFuture继承Runnable、Future
public interface RunnableFuture<
V>
extends Runnable, Future<
V>
{void run();
}
源码中可以看出构造函数中需要传进去一个Callable或者是Runnable, 如果传进去是个Runnable则会被Executors.callable()转换为Callable类型的任务, 即FutureTask最终都是执行Callable类型的任务。继续追踪Executors.callable()
//Executors.callable()方法
public static <
T>
Callable<
T>
callable(Runnable task, T result) {
if (task =
=
null)
throw new NullPointerException();
return new RunnableAdapter<
T>
(task, result);
}//继续追踪RunnableAdapter<
T>
类
private static final class RunnableAdapter<
T>
implements Callable<
T>
{
private final Runnable task;
private final T result;
RunnableAdapter(Runnable task, T result) {
this.task =
task;
this.result =
result;
}
public T call() {
task.run();
return result;
}
}
由于FutureTask实现了Runnable, 因此, 它既可以通过Thread包装来直接运行, 也可以通过给ExecuteService来执行, 并且还可以通过get()方法获取执行结果, 该函数会阻塞, 直到结果返回。下面通过简单的例子演示FutureTask的用法
public class FutureTaskActivity extends AppCompatActivity {@
Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_future_task);
//线程池
ExecutorService executor =
Executors.newFixedThreadPool(10);
//创建线程
MyCallable callable =
new MyCallable();
//包装线程
FutureTask<
String>
futureTask =
new FutureTask<
String>
(callable);
//执行线程
executor.submit(futureTask);
//获取结果
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}public class MyCallable implements Callable<
String>
{@
Override
public String call() throws Exception {
Thread.sleep(2000);
return "
我是Callable返回值"
;
}
}
}
打印信息是
我是Callable返回值
推荐阅读
- 移动支付--银联,支付宝,微信(android)
- Android WebView介绍
- 关于Android中使用SVG特性的探索与总结
- Android编程(UDP客户端和TCP客户端)
- Android6.0 WMS WMS动画管理
- android获取位置location为null的问题
- 转 Android RadioButton设置选中时文字和背景颜色同时改变
- Android Studio第二十六期 - 自定义Activity中Fragment之间的传值
- unity, reduce android size