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 TestFuture
{ public static void main(String[] args) throws InterruptedException, ExecutionException
{
final ExecutorService executor = Executors.newCachedThreadPool();
final Future<String> future = executor.submit(new CallableTest()); System.out.println("continue working"); System.out.println(future.get());
}
} class CallableTest implements Callable<String>
{ @Override
public String call() throws Exception
{
Thread.sleep(5000);
return "Hello World!";
} }

上面的代码很简单,定义了一个Callable对象,利用ExecutorService线程池将Callable对象提交到线程池当中去执行。

本文要详细讲述的就是JDK中怎么通过Future对象来等待任务结果并阻塞线程(get())、取消任务等对任务线程的控制。

---------------------------------------------------------------------------------------------------------------

当将Callable对象、Runnable对象通过ExecutorService当中的submit方法提交到线程池当中的时候,会返回一个Future<T>的对象,通过Future<T>对象可以拿到相应的返回结果

1)提交任务后,主线程是继续向下执行的,因为任务被异步线程去执行了

2)当任务仍未执行完的时候,如果任何一个线程调用Future<T>对象的get()方法想获取返回值得时候,都会将线程阻塞,等任务执行完毕之后,返回结果,线程被唤醒重新执行。

3)这提供了一种共享锁的模型,很多线程都可以通过同一个Future<T>对象阻塞在一个条件上

--------------------------------这种多个线程阻塞和唤醒是怎么做到的呢?----------------------

package java.util.concurrent;

public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    V get() throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}

我们看到Future<V>其实只是一个接口,那么他的实现在哪里呢?

-------------------------------------------

在ExecutorService的实现类AbstractExeccutorService当中的submit(Callable<T> callable)

实现中(submit的作用就是提交一个有返回值的任务给线程池,并且返回一个Future对象来处理返回结果)

    public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}

 

看到返回的是一个RunnableFuture对象,这个对象实现了Runnable和Future的接口

protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}

看到返回的是FutureTask对象其实,包裹了Callable对象

这样其实就可以理解了,FutureTask对象实现了Runnable和Future接口,将FutureTask这个Runnable对象丢到Execcutor线程池当中异步执行(execute(ftask))

最终执行FutureTask对象的run方法,可想而已,在run方法中调用了Callable对象的call方法,并且将返回值赋值给FutureTask对象的成员变量以便get方法获取。

--------------------------------------------

 public void run() {
sync.innerRun();
}

果然我们在FutureTask的run方法中看到调用了Sync对象的innerRun()方法

        void innerRun() {
if (!compareAndSetState(READY, RUNNING))
return; runner = Thread.currentThread();
if (getState() == RUNNING) { // recheck after setting thread
V result;
try {
result = callable.call();
} catch (Throwable ex) {
setException(ex);
return;
}
set(result);
} else {
releaseShared(0); // cancel
}
}

  private final class Sync extends AbstractQueuedSynchronizer

Sync对象是在FutureTask当中的内部类对象

FutureTask源码解读的更多相关文章

  1. Future、FutureTask实现原理浅析(源码解读)

    前言 最近一直在看JUC下面的一些东西,发现很多东西都是以前用过,但是真是到原理层面自己还是很欠缺. 刚好趁这段时间不太忙,回来了便一点点学习总结. 前言 最近一直在看JUC下面的一些东西,发现很多东 ...

  2. ScheduledThreadPoolExecutor源码解读

    1. 背景 在之前的博文--ThreadPoolExecutor源码解读已经对ThreadPoolExecutor的实现原理与源码进行了分析.ScheduledExecutorService也是我们在 ...

  3. ThreadPoolExecutor源码解读

    1. 背景与简介 在Java中异步任务的处理,我们通常会使用Executor框架,而ThreadPoolExecutor是JUC为我们提供的线程池实现. 线程池的优点在于规避线程的频繁创建,对线程资源 ...

  4. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

  5. SDWebImage源码解读 之 NSData+ImageContentType

    第一篇 前言 从今天开始,我将开启一段源码解读的旅途了.在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划.但能够肯定的是,这一系列之中肯定会有Swift版本的代码. 说说 ...

  6. SDWebImage源码解读 之 UIImage+GIF

    第二篇 前言 本篇是和GIF相关的一个UIImage的分类.主要提供了三个方法: + (UIImage *)sd_animatedGIFNamed:(NSString *)name ----- 根据名 ...

  7. SDWebImage源码解读 之 SDWebImageCompat

    第三篇 前言 本篇主要解读SDWebImage的配置文件.正如compat的定义,该配置文件主要是兼容Apple的其他设备.也许我们真实的开发平台只有一个,但考虑各个平台的兼容性,对于框架有着很重要的 ...

  8. SDWebImage源码解读_之SDWebImageDecoder

    第四篇 前言 首先,我们要弄明白一个问题? 为什么要对UIImage进行解码呢?难道不能直接使用吗? 其实不解码也是可以使用的,假如说我们通过imageNamed:来加载image,系统默认会在主线程 ...

  9. SDWebImage源码解读之SDWebImageCache(上)

    第五篇 前言 本篇主要讲解图片缓存类的知识,虽然只涉及了图片方面的缓存的设计,但思想同样适用于别的方面的设计.在架构上来说,缓存算是存储设计的一部分.我们把各种不同的存储内容按照功能进行切割后,图片缓 ...

随机推荐

  1. 自定义toast功能

    http://download.csdn.net/detail/caryt/8105031

  2. iOS上文本绘制的几种方法

    文本绘制在开发客户端程序中是一个比较常用的功能,可分为采用控件和直接绘制两种方式. 采用控件的方式比较简便,添加一个比如UILabel对象,然后设置相关属性就好了.但这种方式局限性也比较大. 直接绘制 ...

  3. 将PL/SQL代码封装在机灵的包中

    将代码封装在机灵的包中 http://www.oracle.com/technetwork/issue-archive/2013/13-jan/o13plsql-1872456.html 绝大多数基于 ...

  4. iOS Runtime 实践(1)

    很多时候我们都在看iOS开发中的黑魔法——Runtime.懂很多,但如何实践却少有人提及.本文便是iOS Runtime的实践第一篇. WebView 我们这次的实践主题,是使用针对接口编程的方式,借 ...

  5. Linux下搭建Oracle11g RAC(6)----安装Grid Infrastructure

    从此步骤开始,我们正式安装Grid软件: ① 以grid用户登录图形界面,执行/home/grid/grid/runInstaller,进入OUI的图形安装界面: ② 进入OUI安装界面后,选择第3项 ...

  6. Ubuntu 13.10 Rhythmbox 播放器不能播放MP3。安装插件

    Ctrl+Alt+T > sudo apt-get install ubuntu-restricted-extras 因为版权和专利的问题,MP3等一些non-free的格式文件支持没有出现在免 ...

  7. SQL Server中建立外键的方法

    在SQL中建立外键约束,可以级联查询表中的数据,在C#代码生成器中,也能根据外键关系生成相应的外键表数据模型.外键也可防止删除有外键关系的记录,一定程度上保护了数据的安全性. 步骤: 1.要建立外键关 ...

  8. codeforces 132C Logo Turtle(dp)

    可以用三维dp来保存状态, dp[i][j][k]表示在前i个字符变换了j步之后方向为k(k = 1 or k = 0)的最优解,也就是离原点的最大距离.这里规定0方向为正方向,1位负方向,表示的是当 ...

  9. Unty3D动态加载图片

    试验动态加载图片,代码如下: using UnityEngine; using System.Collections; public class DynamicLoad : MonoBehaviour ...

  10. android开发:点击缩略图查看大图

    android中点击缩略图查看大图的方法一般有两种,一种是想新浪微博list页面那样,弹出一个窗口显示大图(原activity为背景).另一种就是直接打开一个新的activity显示大图. 1.第一种 ...