博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(原创)Callable、FutureTask中阻塞超时返回的坑点
阅读量:4134 次
发布时间:2019-05-25

本文共 6172 字,大约阅读时间需要 20 分钟。

直接上代码

import java.util.concurrent.Callable; public class MyCallable implements Callable
{ 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(1000);        MyCallable callable2 = new MyCallable(2000);         FutureTask
futureTask1 = new FutureTask
(callable1); FutureTask
futureTask2 = new FutureTask
(callable2); ExecutorService executor = Executors.newFixedThreadPool(2); 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行代码有超时处理。

1 import java.util.concurrent.ExecutionException; 2 import java.util.concurrent.ExecutorService; 3 import java.util.concurrent.Executors; 4 import java.util.concurrent.FutureTask; 5 import java.util.concurrent.TimeUnit; 6 import java.util.concurrent.TimeoutException; 7   8 public class FutureTaskExample { 9  10     public static void main(String[] args) {11         MyCallable callable1 = new MyCallable(1000);12         MyCallable callable2 = new MyCallable(2000);13  14         FutureTask
futureTask1 = new FutureTask
(callable1);15 FutureTask
futureTask2 = new FutureTask
(callable2);16 17 ExecutorService executor = Executors.newFixedThreadPool(2);18 executor.execute(futureTask1);19 executor.execute(futureTask2);20 21 while (true) 22 {23 try {24 if(futureTask1.isDone() && futureTask2.isDone()){25 System.out.println("Done");26 //shut down executor service27 executor.shutdown();28 return;29 }30 31 if(!futureTask1.isDone()){32 //阻塞futureTask133 System.out.println("FutureTask1 output="+futureTask1.get());34 }35 36 System.out.println("Waiting for FutureTask2 to complete");37 String s = futureTask2.get(500L, TimeUnit.MILLISECONDS); //阻塞500毫秒38 if(s !=null){39 System.out.println("FutureTask2 output="+s);40 }41 else{42 System.out.println("FutureTask2 output is null");43 }44 } catch (InterruptedException | ExecutionException e) {45 e.printStackTrace();46 }catch(Exception e){47 //do nothing48 }49 }50 51 }52 53 }

 

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

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            }        }
View Code

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

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

 

你可能感兴趣的文章
文件上传时生成“日期+随机数”式文件名前缀的Java代码
查看>>
Java代码检查工具Checkstyle常见输出结果
查看>>
北京十大情人分手圣地
查看>>
Android自动关机代码
查看>>
Android中启动其他Activity并返回结果
查看>>
2009年33所高校被暂停或被限制招生
查看>>
GlassFish 部署及应用入门
查看>>
iWatch报错: Authorization request cancled
查看>>
iWatch报错: Authorizationsession time out
查看>>
X-code7 beta error: warning: Is a directory
查看>>
Error: An App ID with identifier "*****" is not avaliable. Please enter a different string.
查看>>
X-code beta 开发iWatch项目,运行没有错误,但是某些操作一点就崩,而且找不错误的原因场景一
查看>>
Xcode 报错: Extra argument in call
查看>>
iTunes Connect 上传APP报错: Communication error. please use diagnostic mode to check connectivity.
查看>>
#import <Cocoa/Cocoa.h> 报错 Lexical or Preprocessor Issue 'Cocoa/Cocoa.h' file not found
查看>>
`MQTTClient (~> 0.2.6)` required by `Podfile`
查看>>
X-Code 报错 ld: library not found for -lAFNetworking
查看>>
Bitcode
查看>>
If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
查看>>
3.5 YOLO9000: Better,Faster,Stronger(YOLO9000:更好,更快,更强)
查看>>