1.Future和Callable


Future是一个接口表示异步计算的结果,它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。Future提供了get()、cancel()、isCancel()、isDone()四种方法,表示Future有三种功能:

1、判断任务是否完成

2、中断任务

3、获取任务执行结果

 

Callable和Runnable差不多,两者都是为那些其实例可能被另一个线程执行的类而设计的,最主要的差别在于Runnable不会返回线程运算结果,Callable可以(假如线程需要返回运行结果)

 public class CallableAndFuture {
public static class CallableThread implements Callable<String> { @Override
public String call() throws Exception {
Thread.sleep(3000);
System.out.println("方法A过了3秒钟才返回数据");
return "A返回结果";
} } public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
CallableThread cThread = new CallableThread();
Future<String> submit = newCachedThreadPool.submit(cThread);
System.out.println(submit.get());
} }

输出:

方法A过了3秒才返回结果

2.FutureTask


先上个FutureTask的类图

FutureTask实现了Runnable和Future,实际上是这两个接口的包装器,所以FutureTask既是Runnable也是Future

我们先写个基本的例子看看FutureTask的使用

Callable<Integer> myComputation = ...;
FutureTask<Integer> task = new FutureTask<Integer>(myComputation);
Thread t = new Thread(task);
t.start();
...
Integer result = task.get(); //获取结果

再看下他的构造方法

相比第一个构造方法,第二个构造方法里面把Runnable转成了callable,所以两个构造方法实现的功能其实都差不多。

FutureTask里面最重要的方法就是get方法了,该方法实际上是对Future的get的实现,下面我们研究下FutureTask的代码

1.FutureTask的状态转换过程:

  private static final int NEW = 0; // 任务新建和执行中
  private static final int COMPLETING = 1; // 任务将要执行完毕
  private static final int NORMAL = 2; // 任务正常执行结束
  private static final int EXCEPTIONAL = 3; // 任务异常
  private static final int CANCELLED = 4; // 任务取消
  private static final int INTERRUPTING = 5; // 任务线程即将被中断
  private static final int INTERRUPTED = 6; // 任务线程已经中断

 * NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED

2.具体的get方法如下

实现阻塞效果的是awaitDone,具体如下

 private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
//先定义一堆变量
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
//注意,这个是死循环,阻塞有他一半的功劳
for (;;) {
//刚开始线程还没加入到阻塞队列中这段代码是没有用的,
//这里的作用是当线程已加入队列后,这时候线程被中断了,那就把线程从队列中移除
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
} int s = state;
//任务结束,返回状态
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
//将要结束,那就再等等呗
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
//初始化
else if (q == null)
q = new WaitNode();
//还没加入队列,那就用CAS加进去呗
else if (!queued)
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
//将线程挂起来,这里就阻塞了
else if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
LockSupport.parkNanos(this, nanos);
}
else
LockSupport.park(this);
}
}

上述讲述的是FutureTask的阻塞实现,其实还有个疑惑,当线程运行完毕,阻塞会自动解除获取结果,这究竟是怎么实现的呢

我们看看线程的run方法

这里有个ran变量,当获取到执行结果后ran变量为true,再执行set方法

这个可以看出正常情况下FutureTask的状态变化是

NEW -> COMPLETING -> NORMAL

我们再看出 finishCompletion

哈,找到了,类似于AQS的共享锁,这里也做了持续的唤醒

Future、Callable 、FutureTask详解的更多相关文章

  1. Callable,Future和FutureTask详解

    1.Callable和Runnable 看Callable接口: public interface Callable<V> { /** * Computes a result, or th ...

  2. Java多线程编程中Future模式的详解

    Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...

  3. Java多线程编程中Future模式的详解<转>

    Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...

  4. [转]FutureTask详解

     FutureTask类是Future 的一个实现,并实现了Runnable,所以可通过Excutor(线程池) 来执行,也可传递给Thread对象执行.如果在主线程中需要执行比较耗时的操作时,但又不 ...

  5. 并发编程-Future+callable+FutureTask 闭锁机制

    项目中经常有些任务需要异步(提交到线程池中)去执行,而主线程往往需要知道异步执行产生的结果,这时我们要怎么做呢?用runnable是无法实现的,我们需要用callable实现. FutureTask ...

  6. FutureTask详解

    1 基本概念 1.1 Callable与Future Runnable封装一个异步运行的任务,可以把它想象成为一个没有参数和返回值的异步方法.Callable与Runnable类似,但是有返回值.Ca ...

  7. Java并发编程的艺术笔记(九)——FutureTask详解

    FutureTask是一种可以取消的异步的计算任务.它的计算是通过Callable实现的,多用于耗时的计算. 一.FutureTask的三种状态 二.get()和cancel()执行示意 三.使用 一 ...

  8. JAVA线程池原理详解二

    Executor框架的两级调度模型 在HotSpot VM的模型中,JAVA线程被一对一映射为本地操作系统线程.JAVA线程启动时会创建一个本地操作系统线程,当JAVA线程终止时,对应的操作系统线程也 ...

  9. 跟着阿里p7一起学java高并发 - 第19天:JUC中的Executor框架详解1,全面掌握java并发核心技术

    这是java高并发系列第19篇文章. 本文主要内容 介绍Executor框架相关内容 介绍Executor 介绍ExecutorService 介绍线程池ThreadPoolExecutor及案例 介 ...

随机推荐

  1. PID25 / 合并果子 ☆

    这里用到了STL里面的priority_queue,我也不是很精通基本上属于现学现卖阶段,http://www.cnblogs.com/flyoung2008/articles/2136485.htm ...

  2. HTML5调用手机的Datepicker(日期选择器)

    HTML5 拥有多个新的表单输入类型.这些新特性提供了更好的输入控制和验证,包含了如下新的输入类型: email url number range Date pickers (date, month, ...

  3. Nginx服务器中配置非80端口的端口转发方法详解

    这篇文章主要介绍了Nginx服务器中配置非80端口的端口转发方法详解,文中使用到了Nginx中的proxy_pass配置项,需要的朋友可以参考下 nginx可以很方便的配置成反向代理服务器: 1 2 ...

  4. Notes : <Hands-on ML with Sklearn & TF> Chapter 4

    .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px so ...

  5. 信息安全技能树(SecWiki中Web安全工程师职位建议)

    职位描述: 对公司网站.业务系统进行安全评估测试(黑盒.白盒测试): 对公司各类系统进行安全加固: 对公司安全事件进行响应,清理后门,根据日志分析攻击途径: 安全技术研究,包括安全防范技术,黑客技术等 ...

  6. Open/Close Port in Centos

    1. Show status /etc/init.d/iptables status 2.Set Port iptables -I INPUT -p tcp --dport 80 -j ACCEPT ...

  7. 初见SDN

    软件定义网络(Software Defined Network, SDN ),是一种新型网络架构. SDN=OpenFlow:因为Openflow是大多数人唯一看得到的具体化的SDN的实现形式(实际上 ...

  8. email program (客户端)演变过程有感

    以下内容全部为个人读后感(参考百度百科的相关资料) 首先我认为电子邮件是一个非常伟大的发明,它不仅成本低,而且传输效率快! 关于它的起源,我从百度百科中看到了两种说法     1.1969年10月世界 ...

  9. 【Vue】谈Vue的依赖追踪系统 ——搞懂methods watch和compute的区别和联系

    从作用机制和性质上看待methods,watch和computed的关系 图片标题[原创]:<他三个是啥子关系呢?> 首先要说,methods,watch和computed都是以函数为基础 ...

  10. [W3bsafe]分享一个爬SQL注入漏洞的工具

    分享一个爬SQL注入的工具 本文转自:i春秋社区由团队核心成员若间开发把工具放到E盘的一个文件夹 他会自动生成一个文本文件 Result.txt  最大页数 自己想弄填多少就填多少关键词 注入点关键词 ...