[JAVA学习笔记-64] Future与Callable的关联
来源:互联网 发布:sql出生日期怎么算年龄 编辑:程序博客网 时间:2024/04/28 06:14
一个Future对象与一个被提交到ExecutorService对象去执行的Callable对象相关联,使用Future可以:
1、取消一个Callable任务
2、获取Callable任务的返回值
3、查看Callable任务是否被取消
4、查看Callable任务是否已经完成执行(正常执行完毕,异常退出,被取消)
Future对象与Callable对象是如何关联的?
1、提交给线程池
public <T> Future<T> submit(Callable<T> task) {
return schedule(task, 0, TimeUnit.NANOSECONDS);
}
2、schedule的处理
public <V> ScheduledFuture<V> schedule(Callable<V> callable,
long delay,
TimeUnit unit) {
if (callable == null || unit == null)
throw new NullPointerException();
RunnableScheduledFuture<V> t = decorateTask(callable,new ScheduledFutureTask<V>(callable,triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
说明:
1、public interface ScheduledFuture<V> extends Delayed, Future<V> {}
ScheduledFuture 实质是继承自 Future<V>,因此业务代码用Future<V> 类型的对象接收这个返回的对象即可
2、返回给业务的实质是 RunnableScheduledFuture<V> 对象
public interface RunnableScheduledFuture<V> extends RunnableFuture<V>, ScheduledFuture<V> {
boolean isPeriodic();
}
RunnableScheduledFuture<V> --> ScheduledFuture<V> --> Future<V>
从命名可以看到,RunnableScheduledFuture 具备Future的功能,同时它应该也具备Runnable功能,也就是说,它其实是一个被执行的task对象,
并且这个对象还具备Scheduled功能,即,它是可以被调度的(单次/周期执行)
3、从 delayedExecute(t) 可以看到实际运行的是经过封装的Callable对象,即t,而不是直接运行Callable对象
/**
* Main execution method for delayed or periodic tasks. If pool
* is shut down, rejects the task. Otherwise adds task to queue
* and starts a thread, if necessary, to run it. (We cannot
* prestart the thread to run the task because the task (probably)
* shouldn't be run yet,) If the pool is shut down while the task
* is being added, cancel and remove it if required by state and
* run-after-shutdown parameters.
*
* @param task the task
*/
private void delayedExecute(RunnableScheduledFuture<?> task)
4、关于 decorateTask
protected <V> RunnableScheduledFuture<V> decorateTask(
Callable<V> callable, RunnableScheduledFuture<V> task) {
return task;
}
可见这个方法其实啥也没干,就是返回了 new ScheduledFutureTask<V>(callable,triggerTime(delay, unit)
5、那么我们来看看 ScheduledFutureTask<V> 的构造
public interface RunnableFuture<V> extends Runnable, Future<V>
public class FutureTask<V> implements RunnableFuture<V>
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
FutureTask的构造函数,保存了一个Callable对象。从FutureTask的继承关系,可以看到它将分配一个线程来执行,并且,它具备Future<V>的功能。
private class ScheduledFutureTask<V> extends FutureTask<V> implements RunnableScheduledFuture<V>
从继承关系可以看到,ScheduledFutureTask 实际上是一个 FutureTask ,这样,业务创建的Callable对象,通过FutureTask保存在一个
ScheduledFutureTask 对象中。
综述:
简单地讲,用户提交的Callable对象,最终经过FutureTask的封装,经由线程池分配线程并执行。换句话说,业务代码调用submit返回的Future<V>
对象,正是被线程池执行的那个对象,而由此调用get返回的正是被封装的那个Callable对象本身的result。
由此似乎也可以看到FutureTask存在的意义,即,它同时具备Future以及Task的功能,用它来封装一个Callable对象,只要运行这个Decorated Callable
object,并调用实现的Future<V>接口的get方法,就可以获取这个Callable对象的执行结果了。换句话说,业务代码一般并不需要直接使用FutureTask,使用
Future就可以了。
3、执行结果的返回
task被加入到调度队列,剩下的事情就不在此赘述了。这里我们关注的是Future接口,因此再来看下,get方法是如何实现的。
这是FutureTask的run方法,任务队列的执行线程,应该是通过调用该方法,来调用被封装的Callable对象的call()方法,进而执行的。
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result); //设置Callable对象的执行结果
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
结果的返回:
FutureTask实现了Future接口的get方法:
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
report方法的实现:
private V report(int s) throws ExecutionException {
Object x = outcome;
//这里的outcome,就是run方法中,set(result) 执行后保存result的对象。它被定义成Object,意味着Callable<V>的V必须是
//一个Object对象,而不能是JAVA本身的primitive types,这就是可以用Integer而不能用int的原因,因为get返回的是一个对象。
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
1、取消一个Callable任务
2、获取Callable任务的返回值
3、查看Callable任务是否被取消
4、查看Callable任务是否已经完成执行(正常执行完毕,异常退出,被取消)
Future对象与Callable对象是如何关联的?
1、提交给线程池
public <T> Future<T> submit(Callable<T> task) {
return schedule(task, 0, TimeUnit.NANOSECONDS);
}
2、schedule的处理
public <V> ScheduledFuture<V> schedule(Callable<V> callable,
long delay,
TimeUnit unit) {
if (callable == null || unit == null)
throw new NullPointerException();
RunnableScheduledFuture<V> t = decorateTask(callable,new ScheduledFutureTask<V>(callable,triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
说明:
1、public interface ScheduledFuture<V> extends Delayed, Future<V> {}
ScheduledFuture 实质是继承自 Future<V>,因此业务代码用Future<V> 类型的对象接收这个返回的对象即可
2、返回给业务的实质是 RunnableScheduledFuture<V> 对象
public interface RunnableScheduledFuture<V> extends RunnableFuture<V>, ScheduledFuture<V> {
boolean isPeriodic();
}
RunnableScheduledFuture<V> --> ScheduledFuture<V> --> Future<V>
从命名可以看到,RunnableScheduledFuture 具备Future的功能,同时它应该也具备Runnable功能,也就是说,它其实是一个被执行的task对象,
并且这个对象还具备Scheduled功能,即,它是可以被调度的(单次/周期执行)
3、从 delayedExecute(t) 可以看到实际运行的是经过封装的Callable对象,即t,而不是直接运行Callable对象
/**
* Main execution method for delayed or periodic tasks. If pool
* is shut down, rejects the task. Otherwise adds task to queue
* and starts a thread, if necessary, to run it. (We cannot
* prestart the thread to run the task because the task (probably)
* shouldn't be run yet,) If the pool is shut down while the task
* is being added, cancel and remove it if required by state and
* run-after-shutdown parameters.
*
* @param task the task
*/
private void delayedExecute(RunnableScheduledFuture<?> task)
4、关于 decorateTask
protected <V> RunnableScheduledFuture<V> decorateTask(
Callable<V> callable, RunnableScheduledFuture<V> task) {
return task;
}
可见这个方法其实啥也没干,就是返回了 new ScheduledFutureTask<V>(callable,triggerTime(delay, unit)
5、那么我们来看看 ScheduledFutureTask<V> 的构造
public interface RunnableFuture<V> extends Runnable, Future<V>
public class FutureTask<V> implements RunnableFuture<V>
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
FutureTask的构造函数,保存了一个Callable对象。从FutureTask的继承关系,可以看到它将分配一个线程来执行,并且,它具备Future<V>的功能。
private class ScheduledFutureTask<V> extends FutureTask<V> implements RunnableScheduledFuture<V>
从继承关系可以看到,ScheduledFutureTask 实际上是一个 FutureTask ,这样,业务创建的Callable对象,通过FutureTask保存在一个
ScheduledFutureTask 对象中。
综述:
简单地讲,用户提交的Callable对象,最终经过FutureTask的封装,经由线程池分配线程并执行。换句话说,业务代码调用submit返回的Future<V>
对象,正是被线程池执行的那个对象,而由此调用get返回的正是被封装的那个Callable对象本身的result。
由此似乎也可以看到FutureTask存在的意义,即,它同时具备Future以及Task的功能,用它来封装一个Callable对象,只要运行这个Decorated Callable
object,并调用实现的Future<V>接口的get方法,就可以获取这个Callable对象的执行结果了。换句话说,业务代码一般并不需要直接使用FutureTask,使用
Future就可以了。
3、执行结果的返回
task被加入到调度队列,剩下的事情就不在此赘述了。这里我们关注的是Future接口,因此再来看下,get方法是如何实现的。
这是FutureTask的run方法,任务队列的执行线程,应该是通过调用该方法,来调用被封装的Callable对象的call()方法,进而执行的。
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result); //设置Callable对象的执行结果
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
结果的返回:
FutureTask实现了Future接口的get方法:
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
report方法的实现:
private V report(int s) throws ExecutionException {
Object x = outcome;
//这里的outcome,就是run方法中,set(result) 执行后保存result的对象。它被定义成Object,意味着Callable<V>的V必须是
//一个Object对象,而不能是JAVA本身的primitive types,这就是可以用Integer而不能用int的原因,因为get返回的是一个对象。
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
0 0
- [JAVA学习笔记-64] Future与Callable的关联
- Future,Callable学习笔记
- Java新技术---线程学习之Callable与Future的应用
- Java学习笔记之Callable和Future
- java 之 Callable 与 Future 的应用
- java Callable与Future的介绍
- Java的多线程之Callable与Future
- 【java并发】Callable与Future的应用
- Java并发:Callable与Future的应用
- 张孝祥Callable&Future(学习笔记)
- Java Callable和Future学习
- Java接口:Callable 与 Future
- Java多线程--Future与Callable
- 疯狂Java学习笔记(66)-----------Callable、Future和FutureTask
- java多线程学习笔记:使用Callable和Future
- JAVA学习笔记(三)-并发编程 Callable Future CompleableFuture
- 以Android环境为例的多线程学习笔记(四)----------Callable与Future
- 以Android环境为例的多线程学习笔记———-Callable与Future
- Java算法4-- 图像压缩算法执行过程
- 【笔记】进制转换
- 第五周 项目一(6)前一百项和(Raptor)
- 轮播
- C++并发编程2——为共享数据加锁(二)
- [JAVA学习笔记-64] Future与Callable的关联
- 第五周:Raptor:选择结构。
- 第五周项目3--输入一个数与0比较(LOW or HIGH)
- [JAVA学习笔记-62]inputstream及几个相关的类
- 事物
- 第一、二章 感知器和BP算法
- C++并发编程2——为共享数据加锁(三)
- gnu make关键点解释
- Java高手真经为您规划Java技术体系