相关文章推荐
酷酷的橙子  ·  SetWindowsHookExW 函数 ...·  3 周前    · 
憨厚的水煮肉  ·  paddle2onnx ...·  2 月前    · 
安静的包子  ·  Alternative approach ...·  4 月前    · 
乐观的皮带  ·  请帮忙添加代码,excel ...·  12 月前    · 
坚强的山楂  ·  聊一聊全景图 - 知乎·  1 年前    · 

Callable接口和Future接口介绍

Java 中,如果需要设定代码执行的最长时间,即超时,可以用 Java线程池ExecutorService 类配合Future接口来实现。 Future接口是Java标准API的一部分,在java.util.concurrent包中。Future接口是Java线程Future模式的实现,可以来进行异步计算。

Future模式可以这样来描述:我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时间之后,我就便可以从Future那儿取出结果。就相当于下了一张订货单,一段时间后可以拿着提订单来提货,这期间可以干别的任何事情。其中Future 接口就是订货单,真正处理订单的是Executor类,它根据Future接口的要求来生产产品。

Future接口提供方法来检测任务是否被执行完,等待任务执行完获得结果,也可以设置任务执行的超时时间。这个设置超时的方法就是实现Java程序执行超时的关键。

Future接口是一个泛型接口,严格的格式应该是Future<V>,其中V代表了Future执行的任务返回值的类型。 Future接口的方法介绍如下:

  • boolean cancel (boolean mayInterruptIfRunning) 取消任务的执行。参数指定是否立即中断任务执行,或者等等任务结束
  • boolean isCancelled () 任务是否已经取消,任务正常完成前将其取消,则返回 true
  • boolean isDone () 任务是否已经完成。需要注意的是如果任务正常终止、异常或取消,都将返回true
  • V get () throws InterruptedException, ExecutionException  等待任务执行结束,然后获得V类型的结果。InterruptedException 线程被中断异常, ExecutionException任务执行异常,如果任务被取消,还会抛出 CancellationException
  • V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 同上面的get功能一样,多了设置超时时间。参数timeout指定超时时间,uint指定时间的单位,在枚举类TimeUnit中有相关的定义。如果计算超时,将抛出TimeoutException

Future的实现类有java.util.concurrent.FutureTask<V>即 javax.swing.SwingWorker<T,V>。通常使用FutureTask来处理我们的任务。 FutureTask类同时又实现了Runnable接口,所以可以直接提交给Executor执行 。使用FutureTask实现超时执行的代码如下:

  1. ExecutorService executor = Executors.newSingleThreadExecutor();
  2. FutureTask<String> future =
  3. new FutureTask<String>( new Callable<String>() { //使用Callable接口作为构造参数
  4. public String call() {
  5. //真正的任务在这里执行,这里的返回值类型为String,可以为任意类型
  6. }});
  7. executor.execute(future);
  8. //在这里可以做别的任何事情
  9. try {
  10. result = future.get( 5000 , TimeUnit.MILLISECONDS); //取得结果,同时设置超时执行时间为5秒。同样可以用future.get(),不设置执行超时时间取得结果
  11. } catch (InterruptedException e) {
  12. futureTask.cancel( true );
  13. } catch (ExecutionException e) {
  14. futureTask.cancel( true );
  15. } catch (TimeoutException e) {
  16. futureTask.cancel( true );
  17. } finally {
  18. executor.shutdown();
  19. }
不直接构造Future对象,也可以使用ExecutorService.submit方法来获得Future对象,submit方法即支持以 Callable接口类型,也支持Runnable接口作为参数,具有很大的灵活性。使用示例如下:
  1. ExecutorService executor = Executors.newSingleThreadExecutor();
  2. FutureTask<String> future = executor.submit(
  3. new Callable<String>() { //使用Callable接口作为构造参数
  4. public String call() {
  5. //真正的任务在这里执行,这里的返回值类型为String,可以为任意类型
  6. }});
  7. //在这里可以做别的任何事情
  8. //同上面取得结果的代码
利用Future接口实现程序执行超时大致用法就这么多,改天需要研究下Future接口的内部实现,特别是设定执行超时的实现。

转载自 http://westyi.javaeye.com/blog/714935

例子和注意事项

例1:try catch在for循环之外
  1. package testexception;
  2. import java.util.concurrent.Callable;
  3. import java.util.concurrent.ExecutionException;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. import java.util.concurrent.FutureTask;
  7. import java.util.concurrent.TimeUnit;
  8. import java.util.concurrent.TimeoutException;
  9. public class FutureTaskTest{
  10. public static void main(String[] args) {
  11. ExecutorService executor = Executors.newSingleThreadExecutor();
  12. FutureTask<String> futureTask =
  13. new FutureTask<String>( new Callable<String>() { //使用Callable接口作为构造参数
  14. public String call() {
  15. try {
  16. for ( int i = 0 ; i < 5 ; i++) {
  17. Thread.sleep( 1000 );
  18. System.out.println( "------------------------" +i);
  19. }
  20. } catch (InterruptedException e) {
  21. System.out.println( "InterruptedException1111111" );
  22. e.printStackTrace();
  23. }
  24. //真正的任务在这里执行,这里的返回值类型为String,可以为任意类型
  25. return "call result" ;
  26. }});
  27. executor.execute(futureTask);
  28. //在这里可以做别的任何事情
  29. try {
  30. String result = futureTask.get( 3000 , TimeUnit.MILLISECONDS);
  31. //取得结果,同时设置超时执行时间为5秒。同样可以用future.get(),不设置执行超时时间取得结果
  32. System.out.println( "___________" +result+ "_______________" );
  33. } catch (InterruptedException e) {
  34. System.out.println( "InterruptedException222222" );
  35. futureTask.cancel( true );
  36. } catch (ExecutionException e) {
  37. System.out.println( "InterruptedException333333333" );
  38. futureTask.cancel( true );
  39. } catch (TimeoutException e) {
  40. System.out.println( "!!!!!!!!Time out!!!!!!!!!!" );
  41. futureTask.cancel( true );
  42. } finally {
  43. executor.shutdown();
  44. }
  45. }
  46. }

输出结果: ------------------------0
------------------------1 ------------------------2
!!!!!!!!Time out!!!!!!!!!!
InterruptedException1111111
java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at testexception.FutureTaskTest$1.call(FutureTaskTest.java:20) at testexception.FutureTaskTest$1.call(FutureTaskTest.java:1) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) at java.util.concurrent.FutureTask.run(FutureTask.java:138) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619)

说明:3秒之内没有执行完所以抛了TimeoutException异常,并取消了线程,可以看到后面就没有输出3,4了。注意这里call()函数中, try catch在for循环之外 ,这样执行结果是没有问题的,是我们想要的结果;但是,如果把try catch写在了for循环之内,结果会怎样呢,请看下例。另外,result值即为call()函数返回的值本例中为“call result”。

例子2:try catch在for循环之内

  1. package testexception;
  2. import java.util.concurrent.Callable;
  3. import java.util.concurrent.ExecutionException;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. import java.util.concurrent.FutureTask;
  7. import java.util.concurrent.TimeUnit;
  8. import java.util.concurrent.TimeoutException;
  9. public class FutureTaskTest{
  10. public static void main(String[] args) {
  11. ExecutorService executor = Executors.newSingleThreadExecutor();
  12. FutureTask<String> futureTask =
  13. new FutureTask<String>( new Callable<String>() { //使用Callable接口作为构造参数
  14. public String call() {
  15. for ( int i = 0 ; i < 5 ; i++) {
  16. try {
  17. Thread.sleep( 1000 );
  18. System.out.println( "------------------------" +i);
  19. } catch (InterruptedException e) {
  20. System.out.println( "InterruptedException1111111" );
  21. e.printStackTrace();
  22. }
  23. }
  24. //真正的任务在这里执行,这里的返回值类型为String,可以为任意类型
  25. return "call result" ;
  26. }});
  27. executor.execute(futureTask);
  28. //在这里可以做别的任何事情
  29. try {
  30. String result = futureTask.get( 3000 , TimeUnit.MILLISECONDS);
  31. //取得结果,同时设置超时执行时间为5秒。同样可以用future.get(),不设置执行超时时间取得结果
  32. System.out.println( "___________" +result+ "_______________" );
  33. } catch (InterruptedException e) {
  34. System.out.println( "InterruptedException222222" );
  35. futureTask.cancel( true );
  36. } catch (ExecutionException e) {
  37. System.out.println( "InterruptedException333333333" );
  38. futureTask.cancel( true );
  39. } catch (TimeoutException e) {
  40. System.out.println( "!!!!!!!!Time out!!!!!!!!!!" );
  41. futureTask.cancel( true );
  42. } finally {
  43. executor.shutdown();
  44. }
  45. }
  46. }
输出结果:

------------------------0
------------------------1
------------------------2
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
!!!!!!!!Time out!!!!!!!!!!
InterruptedException1111111
at testexception.FutureTaskTest$1.call(FutureTaskTest.java:20)
at testexception.FutureTaskTest$1.call(FutureTaskTest.java:1)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
------------------------4

说明:根据输出结果可以看到 只有线程3被中断了,后面线程并没有按照我们希望的超时之后就停下来,即使我们在超时异常里面取消了线程 。也就是说,try catch在for循环之内时,取消线程后会让线程中断,所以第四次循环未执行完即被中断,抛出中断异常,然而这个中断异常被for循环之内的线程中断异常catch捕获到,所以 它仍会继续后面的循环输出 。但其实现在的线程已经被标识为中断了,如果你在超时异常catch块中输出futureTask.isCancelled(),你会发现返回的是true。使用时要特别注意这种容易出错的情况。

来源URL:http://blog.csdn.net/zlj526/article/details/40782027Callable接口和Future接口介绍        在Java中,如果需要设定代码执行的最长时间,即超时,可以用Java线程池ExecutorService类配合Future接口来实现。 Future接口是Java标准API的一部分,在java.util 原理是新建一个 Callable 线程 (call方法可以返回对象),用 Future Task封装后,通过 future 对象的get方法来设定 超时 限制。如果 超时 ,则 future .cancel(true)取消执行。 重写 Callable 的call方法,在call方法中调用需要 超时 设置 接口 (在这里是listQuery())。 Callable 线程 我们放到 线程 池里执行。 import java .util.*; import java .util.concurrent.*; public class Main {
Java 中,如果需要设定代码执行的最 时间 ,即 超时 ,可以用 Java 线程 池ExecutorService类配合 Future 接口 来实现。 Future 接口 Java 标准API的一部分,在 java .util.concurrent包中。 Future 接口 Java 线程 Future 模式的实现,可以来进行异步计算。 Future 模式可以这样来描述:我有一个任务,提交给了 Future ,Fu
前段 时间 在搞一个批量处理程序,涉及到 多线程 操作。但是后台服务很不给力,并发一大常常就挂了, 时间 不给返回,导致我的程序也挂死在那里……  那么能不能 设置 一段代码执行的 超时 时间 呢?如果处理 超时 就忽略该错误继续向下执行。  可是在网上搜了大半天,找到的都是无用的代码,根本不能用。  查了大量资料后发现, java 早已经给我们提供了解决方案。jdk1.5自带的并发库中 Future 类就能满
线程 多线程 任务调用,串行阻塞式运行,虽然慢但稳妥要求单个 线程 运行时必须要有 超时 时间 超时 则放弃运行下一个任务这里的实现仅能用,不完善Main. java 运行结果:
今天在项目开发中需要用到对执行方法加上 时间 控制 ,如果方法执行过 则跳出执行,废话不说,直接上代码,用的是 线程 池配合 Callable Future 方式对执行方法的 超时 阻断。希望各位牛人指正  //启用 线程 池 final ExecutorService exec = Executors.newFixedThreadPool(1); Callable >