直接上代码

import java.util.concurrent.Callable;

public class MyCallable implements Callable<String> {

    private long waitTime;

    public MyCallable(int timeInMillis){
this.waitTime=timeInMillis;
}
@Override
public String call() throws Exception {
Thread.sleep(waitTime);
return Thread.currentThread().getName();
} }

结果阻塞的代码

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; public class FutureTaskExample { public static void main(String[] args) {
MyCallable callable1 = new MyCallable();
MyCallable callable2 = new MyCallable(); FutureTask<String> futureTask1 = new FutureTask<String>(callable1);
FutureTask<String> futureTask2 = new FutureTask<String>(callable2); ExecutorService executor = Executors.newFixedThreadPool();
executor.execute(futureTask1);
executor.execute(futureTask2); while (true)
{
try {
if(futureTask1.isDone() && futureTask2.isDone()){
System.out.println("Done");
//shut down executor service
executor.shutdown();
return;
} if(!futureTask1.isDone()){
//阻塞futureTask1
System.out.println("FutureTask1 output="+futureTask1.get());
} if(!futureTask2.isDone()){
//阻塞futureTask2
System.out.println("FutureTask2 output="+futureTask2.get());
} } catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}catch(Exception e){
//do nothing
}
} } }

运行结果很简单,必须是:

FutureTask1 output=pool-1-thread-1
FutureTask2 output=pool-1-thread-2
Done

如果改为阻塞超时,先猜猜输出结果是什么。注意第37行代码有超时处理。

 import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; public class FutureTaskExample { public static void main(String[] args) {
MyCallable callable1 = new MyCallable();
MyCallable callable2 = new MyCallable(); FutureTask<String> futureTask1 = new FutureTask<String>(callable1);
FutureTask<String> futureTask2 = new FutureTask<String>(callable2); ExecutorService executor = Executors.newFixedThreadPool();
executor.execute(futureTask1);
executor.execute(futureTask2); while (true)
{
try {
if(futureTask1.isDone() && futureTask2.isDone()){
System.out.println("Done");
//shut down executor service
executor.shutdown();
return;
} if(!futureTask1.isDone()){
//阻塞futureTask1
System.out.println("FutureTask1 output="+futureTask1.get());
} System.out.println("Waiting for FutureTask2 to complete");
String s = futureTask2.get(500L, TimeUnit.MILLISECONDS); //阻塞500毫秒
if(s !=null){
System.out.println("FutureTask2 output="+s);
}
else{
System.out.println("FutureTask2 output is null");
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}catch(Exception e){
//do nothing
}
} } }

如果说是这样的结果,那就错了

FutureTask1 output=pool-1-thread-1
Waiting for FutureTask2 to complete
FutureTask2 output is null
Waiting for FutureTask2 to complete
FutureTask2 output is null
FutureTask2 output=pool-1-thread-2
Done

最终输出

FutureTask1 output=pool-1-thread-1
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
FutureTask2 output=pool-1-thread-2
Done

说明了一件事,即在超时期限内,如果未能获取线程返回值,futureTask2.get(500L, TimeUnit.MILLISECONDS) 将不对继续执行后面的代码,而是进行下一次的while操作了(并不是返回null),while的下一次循环,直到获取到了返回结果,String s才得以赋值,代码继续进行。

所以要慎用get(long timeout, TimeUnit unit)。

传统的理解是错误的:

get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。

大神 海子 曾对这个问题有质疑,认为会抛出异常,并赋空值,见:

http://www.cnblogs.com/dolphin0520/p/3949310.html#3318489

我尝试修改代码

String s="aa";
while (true)
{
try {
if(futureTask1.isDone() && futureTask2.isDone()){
System.out.println("Done");
//shut down executor service
executor.shutdown();
return;
} if(!futureTask1.isDone()){
//阻塞futureTask1
System.out.println("FutureTask1 output="+futureTask1.get());
} System.out.println("Waiting for FutureTask2 to complete");
s = futureTask2.get(500L, TimeUnit.MILLISECONDS); //阻塞500毫秒
if(s !=null){
System.out.println("FutureTask2 output="+s);
}
else{
System.out.println("FutureTask2 output is null");
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}catch(Exception e){
System.out.println("s is:"+s);
//do nothing
}
}

s的预设值那里有改变:String s="aa";也没发现变为null,是没发生赋值。在异常中s也没有被赋空值。

所以在使用get(long timeout, TimeUnit unit)的时候,变量初始最好能给一个空值,这样就不会产生奇怪的结果,这也是合理的编程习惯。

(原创)Callable、FutureTask中阻塞超时返回的坑点的更多相关文章

  1. 【转载】Callable、FutureTask中阻塞超时返回的坑点

    本文转载自:http://www.cnblogs.com/starcrm/p/5010863.html 案例1: package com.net.thread.future; import java. ...

  2. ExecutorService、Callable、Future实现有返回结果的多线程原理解析

    原创/朱季谦 在并发多线程场景下,存在需要获取各线程的异步执行结果,这时,就可以通过ExecutorService线程池结合Callable.Future来实现. 我们先来写一个简单的例子-- pub ...

  3. java笔记--用ThreadLocal管理线程,Callable<V>接口实现有返回值的线程

    用ThreadLocal管理线程,Callable<V>接口实现有返回值的线程 ThreadLocal在我的笔记"关于线程同步"的第5种方式里面有介绍,这里就不多说了. ...

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

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

  5. 【原创】Matlab中plot函数全功能解析

    [原创]Matlab中plot函数全功能解析 该帖由Matlab技术论(http://www.matlabsky.com)坛原创,更多精彩内容参见http://www.matlabsky.com 功能 ...

  6. [译]async/await中阻塞死锁

    这篇博文主要是讲解在async/await中使用阻塞式代码导致死锁的问题,以及如何避免出现这种死锁.内容主要是从作者Stephen Cleary的两篇博文中翻译过来. 原文1:Don'tBlock o ...

  7. Shiro中session超时页面跳转的处理

    问题描述 shiro在管理session后,在session超时会进行跳转,这里有两种情况需要考虑,一种是ajax方式的请求超时,一种页面跳转请求的超时. 本文从这两个方面分别考虑并处理. ajax请 ...

  8. nginx中的超时配置

    nginx.conf配置文件中timeout超时时间设置 client_header_timeout 语法 client_header_timeout time默认值 60s上下文 http serv ...

  9. Android中Activity处理返回结果的实现方式

    大家在网上购物时都有这样一个体验,在确认订单选择收货人以及地址时,会跳转页面到我们存入网站内的所有收货信息(包含收货地址,收货人)的界面供我们选择,一旦我们点击其中某一条信息,则会自动跳转到订单提交界 ...

随机推荐

  1. 2018.06.27 POJ3281 Dining(最大流)

    Dining Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 21578 Accepted: 9545 Description C ...

  2. NIO原理解析

    NIO中主要包括几大组件,selector.channel.buffer.selector后面介绍,channel则类似于BIO中的流,但是流的读取是单向的,例如只能读,或只能写,但是channel则 ...

  3. HTML5 通过 FileReader 实现文件上传

    概述 在页面中上传时,之前一般都是需要使用form表单进行上传.html5 中提供了FileReader 可以将文件转换成Base64编码字符串,因此就可以直接使用 AJAX实现文件上传. 实现代码 ...

  4. Mybatis-Plus 实战完整学习笔记(六)------select测试一

    查询方法(3.0.3) 1.查询一个员工的数据 @Test public void selectMethod() throws SQLException { // 根据ID获取一个对象的数据 Empl ...

  5. UIActivityIndicatorView 的使用

    // //  UIActivityIndicator.m //  ToolBar // //  Created by lanouhn on 15/1/3. //  Copyright (c) 2015 ...

  6. java通过poi编写excel文件

    public String writeExcel(List<MedicalWhiteList> MedicalWhiteList) { if(MedicalWhiteList == nul ...

  7. USTC《现代软件工程》春季学期——第一次个人作业:词频统计

    截止日期 2018年3月29日23:59 要求 1. 对源文件(*.txt,*.cpp,*.h,*.cs,*.html,*.js,*.java,*.py,*.php等,文件夹内的所有文件)统计字符数. ...

  8. hdu 5086 数列连续和求和

    http://acm.hdu.edu.cn/showproblem.php?pid=5086 求一段数列里面所有连续和的和,卡精度 规律很明显,数列里面每个数都被加了i*(n+1-i)次 注意下精度即 ...

  9. Scala_特质

    特质 特质概述 Java中提供了接口,允许一个类实现任意数量的接口 在Scala中没有接口的概念,而是提供了“特质(trait) ”,它不仅实 现了接口的功能,还具备了很多其他的特性 Scala的特质 ...

  10. ace富文本编辑器

    在线文本编辑器(ACE Editor) ACE是一个实现了语法着色功能的基于Web的代码编辑器,具有良好的代码提示功能和大量的主题. 一.资源获取 官方网址:https://ace.c9.io/ Gi ...