
当我们程序在处理长时间运行的任务时(例如网络连接或计算密集型任务时),通常需要设置超时时间,避免由于资源被长时间占用而影响系统其他功能的正常执行。Java 中有多个方式可以实现该功能需求,假设我们有一个如下耗时方法,每隔 1 秒打印一段信息,总共持续 10 秒:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// 耗时的方法
public static Object longRunningMethod() {
for ( int i = 0 ; i < 10 ; i++) {
System.out.println( "这是第" + (i + 1 ) + "次打印" );
try {
//等待1秒
Thread.sleep( 1000 );
} catch (InterruptedException e) {
e.printStackTrace();
return null ;
}
}
return "完成" ;
}
|
下面分别使用 3 种方式来实现任务超时取消功能。
1,使用线程池和 Future 实现
(1)该方法是通过基于异步任务结果的获取来实现的,具体流程如下:
- 首先创建了一个新的线程池 executor 和一个新的 CompletionService,用于监控要限制时间的方法的执行情况。
- 然后,我们使用 completionService.submit() 方法提交要执行的方法,该方法会返回一个 Future 对象。
- 接着使用 completionService.poll() 方法来获取执行结果。如果该方法在超时时间内执行完毕,则会返回执行结果,我们可以对执行结果进行处理;如果该方法超时了,可以调用 Future 对象的 cancel() 方法来取消任务。
(2)样例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
public class Test {
public static void main(String[] args) {
// 定义超时时间为3秒
long timeout = 3000 ;
// 创建一个新的线程池,用于执行要限制时间的方法
Executor executor = Executors.newSingleThreadExecutor();
// 创建一个新的CompletionService,用于监控执行时间
CompletionServicecompletionService = new ExecutorCompletionService<>(executor);
// 提交要执行的方法
Future future = completionService.submit( new Callable() {
public Object call() throws Exception {
// 这里是要执行的方法
return longRunningMethod();
}
});
// 获取执行结果
try {
Object result = completionService.poll(timeout, TimeUnit.MILLISECONDS);
if (result == null ) {
System.out.println( "超时了,结束该方法的执行" );
future.cancel( true );
} else {
// 方法执行完毕,处理执行结果
System.out.println( "方法执行完毕,结果:" + result.toString());
}
} catch (InterruptedException e) {
System.out.println( "出现异常,结束该方法的执行" );
future.cancel( true );
}
}
}
|

2,使用 FutureTask 实现
(1)我们还可以使用 Java 5 新增的 java.util.concurrent.FutureTask 类来限制方法的执行时间,具体流程如下:
- 首先创建了一个 FutureTask 对象,用于监控要限制时间的方法的执行情况。
- 然后使用 new Thread(futureTask).start() 方法在新线程中执行要限制时间的方法,并使用 futureTask.get() 方法来获取执行结果。如果该方法在超时时间内执行完毕,则会返回执行结果。如果该方法超时了,则会抛出异常,我们在异常处理中调用 futureTask.cancel() 方法取消任务。
(2)样例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
public class Test {
public static void main(String[] args) {
// 定义超时时间为3秒
long timeout = 3000 ;
// 创建一个新的FutureTask
FutureTaskfutureTask = new FutureTask( new Callable() {
public Object call() throws Exception {
// 这里是要执行的方法
return longRunningMethod();
}
});
// 提交要执行的方法
new Thread(futureTask).start();
// 获取执行结果
try {
Object result = futureTask.get(timeout, TimeUnit.MILLISECONDS);
System.out.println( "方法执行完毕,结果:" + result.toString());
} catch (InterruptedException e) {
System.out.println( "出现异常,结束该方法的执行" );
futureTask.cancel( true );
} catch (ExecutionException e) {
System.out.println( "出现异常,结束该方法的执行" );
futureTask.cancel( true );
} catch (TimeoutException e) {
// 超时了,结束该方法的执行
System.out.println( "超时了,结束该方法的执行" );
futureTask.cancel( true );
}
}
}
|
3,使用 CompletableFuture 实现
(1)最简单的方法还是使用 Java 8 新增的 java.util.concurrent.CompletableFuture 类来限制方法的执行时间,具体流程如下:
- 首先创建了一个 CompletableFuture 对象,用于监控要限制时间的方法的执行情况。
- 然后,我们使用 CompletableFuture.supplyAsync() 方法提交要执行的方法,并使用 future.get() 方法来获取执行结果。如果该方法在超时时间内执行完毕,则会返回执行结果。如果该方法超时了,则会抛出异常,我们在异常处理中调用 future.cancel() 方法取消任务。
(2)样例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
public class Test {
public static void main(String[] args) {
// 定义超时时间为3秒
long timeout = 3000 ;
// 创建一个新的CompletableFuture
CompletableFuturefuture = CompletableFuture.supplyAsync(() -> {
// 这里是要执行的方法
return longRunningMethod();
});
// 获取执行结果
try {
Object result = future.get(timeout, TimeUnit.MILLISECONDS);
System.out.println( "方法执行完毕,结果:" + result.toString());
} catch (InterruptedException e) {
System.out.println( "出现异常,结束该方法的执行" );
future.cancel( true );
} catch (ExecutionException e) {
System.out.println( "出现异常,结束该方法的执行" );
future.cancel( true );
} catch (TimeoutException e) {
// 超时了,结束该方法的执行
System.out.println( "超时了,结束该方法的执行" );
future.cancel( true );
}
}
}
|