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实现超时执行的代码如下:

ExecutorService executor = Executors.newSingleThreadExecutor();  
FutureTask<String> future =  
       new FutureTask<String>(new Callable<String>() {//使用Callable接口作为构造参数  
         public String call() {  
           //真正的任务在这里执行,这里的返回值类型为String,可以为任意类型  
executor.execute(future);  
//在这里可以做别的任何事情  
try {  
    result = future.get(5000, TimeUnit.MILLISECONDS); //取得结果,同时设置超时执行时间为5秒。同样可以用future.get(),不设置执行超时时间取得结果  
} catch (InterruptedException e) {  
    futureTask.cancel(true);  
} catch (ExecutionException e) {  
    futureTask.cancel(true);  
} catch (TimeoutException e) {  
    futureTask.cancel(true);  
} finally {  
    executor.shutdown();  
}  
例1try catch在for循环之外, futureTask.cancel(true); 取消后不再执行;try catch在for循环内, futureTask.cancel(true); 取消后继续执行 package testexception; import java.util.concurrent.Callable; 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 FutureTaskTest{ public static void main(String[] args) { ExecutorService executor = Executors.newSingleThreadExecutor(); FutureTask futureTask = new FutureTask (new Callable () {//使用Callable接口作为构造参数 public String call() { * 例1:try catch在for循环之外, futureTask.cancel(true); 取消后不再执行; try { for (int i = 0; i < 5; i++) { Thread.sleep(1000); System.out.println("------------------------"+i); } catch (InterruptedException e) { System.out.println("InterruptedException "); e.printStackTrace(); } */ //try catch在for循环内, futureTask.cancel(true); 取消后继续执行 try { for (int i = 0; i < 5; i++) { Thread.sleep(1000); System.out.println("------------------------"+i); } catch (InterruptedException e) { System.out.println("InterruptedException1111111"); e.printStackTrace(); //真正的任务在这里执行,这里的返回值类型为String,可以为任意类型 return "call result"; executor.execute(futureTask); //在这里可以做别的任何事情 try { String result = futureTask.get(3000, TimeUnit.MILLISECONDS); //取得结果,同时设置超时执行时间为5秒。同样可以用future.get(),不设置执行超时时间取得结果 System.out.println("___________"+result+"_______________"); } catch (InterruptedException e) { System.out.println("InterruptedException "); futureTask.cancel(true); } catch (ExecutionException e) { System.out.println("ExecutionException "); futureTask.cancel(true); } catch (TimeoutException e) { System.out.println("!!!!!!!!Time out!!!!!!!!!!"); futureTask.cancel(true); //取消执行的线程 } finally { executor.shutdown(); 方法一:使用Thread.join(long million)(先讲一下本人对join方法的理解,已理解此方法的可以略过)join方法可以这样理解,在理解它之前,先解释另一个常识,即当前 线程 (后面称为目标 线程 ,因为它是我们想使其 超时 结束的目标任务)的创建及start的调用,一定是在另一个 线程 中进行的(最起码是main 线程 ,也可以是不同于main 线程 的其他 线程 ),这里我们假设为main 线程 ,并且称之... public static void main(String[] args){ System.out.println("执行第一部分代码。。。。"); System.out.println(new Testk().test()); System.out.println("执行第三部分代码。。。。"); private String test(){ String result = ""; final... 今天在项目开发中需要用到对执行方法加上 时间 控制 ,如果方法执行过长则跳出执行,废话不说,直接上代码,用的是 线程 池配合 Callable Future 方式对执行方法的 超时 阻断。希望各位牛人指正  //启用 线程 池 final ExecutorService exec = Executors.newFixedThreadPool(1); Callable > 项目中有时我们需要更新很多记录的不同信息,因为数量多,操作耗时不确定,时长时短,还有可能操作到半卡住,既不断开也没返回结果,有可能等待数天的情况,这肯定不是我们希望的,所以在设计时我们希望,任务列表执行时,能主动 控制 方法执行的 超时 时间 ,如果 超时 了或有异常就抛出异常,同时每次触发进行具体的业务操作又是一连串完整的业务流程操作;串行处理是可以完成,但可能等待的 时间 比较长,所以设法有多路并行触发业务方法... public class Main2 { // 定义 线程 池,推荐手动创建 线程 池: https://blog.csdn.net/LLLLLiSHI/article/details/88057655 private static Exec... 原理是新建一个 Callable 线程 (call方法可以返回对象),用 Future Task封装后,通过 future 对象的get方法来设定 超时 限制。如果 超时 ,则 future .cancel(true)取消执行。 重写 Callable 的call方法,在call方法中调用需要 超时 设置 接口 (在这里是listQuery())。 Callable 线程 我们放到 线程 池里执行。 import java .util.*; import java .util.concurrent.*; public class Main { 在call()未执行完毕之前,调用get()的 线程 (假定此时是主 线程 )会被阻塞,直到call方法返回了结果后,此时 future .get才会得到结果,然后主 线程 才会切换到runnable状态 使用Thread.join(long million)方法,参数是毫秒 代码&解析如下: 解析:原本有t1和t2两个 线程 ,根据实例化new Task()时t1传入了4,t2传入了2,分别相当于t1需要执行4次,t2需要执行2次,但是在run方法中使用了Thread.sleep(1000),所以t1执行4次就等于是执行4秒,t2同理。在t1.start启动后,调用了join方法 设置 了两秒的参数,相当于在t1执行两秒后就 超时 了,后面就是t1 超时 后的 设置 , 1、t1.interrupt()表示打断t1 线程 通常我们创建 线程 的2种方式,一种是直接继承Thread,另外一种就是实现Runnable 接口 。 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。 如果需要获取执行结果,就必须通过共享变量或者使用 线程 通信的方式来达到效果,这样使用起来就比较麻烦。 在JDK1.5之后,就有了 Callable Future ,通过他们可以在任务结束之后得到任务执行结果。 1. Callable 介绍 Calla... 肯定不行,后端可以把3个块的信息,包装成一个 接口 ,全部返回,那么问题来了,后端调用3个 接口 ,比如第一个 接口 需要1秒,第二个需要2秒,第三个需要3秒,那么包装的这个 接口 响应 时间 最少6秒,怎么解决这个问题呢,可以用 多线程 来帮我们解决。启动3个 线程 ,每个 线程 去调用一个 接口 ,那么3个 线程 一共执行完的 时间 就是最慢的那个 线程 的执行 时间 ,这样 接口 的响应 时间 就变成了3秒,一下节省了一半的 时间 线程 没有执行完,也就是没有到达COMPLETING的状态,会执行LockSupport.park,让 线程 等待,那什么时候去唤醒呢? import com.alibaba.fastjson.JSON; import com.trs.tcm.server.DebugTask; import com.trs.tcm.server.Task; import com.trs.util.RedisUtil; import org.junit.Test; import ... 我们写一个有 超时 功能的 Callable :import java .util.concurrent.*;public class Timeout Callable implements Callable {private final Callable callable ;private final V timeoutV;private final long timeout;/*** 构造一个 Timeo...