基本思路是利用future的get方法的超时获取功能包装任务线程,在抛出超时异常时调用future.cancel方法取消执行任务线程
代码如下。其中TaskDemo类是任务线程,TimeOuter类是用来包装任务线程的超时线程:
TaskDemo:
public class TaskDemo implements Runnable {
private long sleep;
public TaskDemo(long sleep) {
this.sleep = sleep;
}
@Override
public void run() {
long start = System.currentTimeMillis();
System.out.println("start.");
try {
TimeUnit.MILLISECONDS.sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end with times. " + (System.currentTimeMillis() - start));
}
}
TimeOuter:
public class TimeOuter implements Runnable {
private final ExecutorService executor = Executors.newSingleThreadExecutor();
private Runnable runnable;
private long timeout;
private TimeUnit timeUnit;
public TimeOuter(Runnable runnable) {
this.runnable = runnable;
this.timeout = 60L;
this.timeUnit = TimeUnit.SECONDS;
}
public TimeOuter(Runnable runnable, long timeout, TimeUnit timeUnit) {
this.runnable = runnable;
this.timeout = timeout;
this.timeUnit = timeUnit;
}
@Override
public void run() {
Future<?> future = executor.submit(runnable);
try {
future.get(timeout, timeUnit);
} catch (TimeoutException e) {
e.printStackTrace();
// 此处调用cancel方法终止任务线程
future.cancel(true);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
测试类如下
public class MainTests {
Executor executor = Executors.newCachedThreadPool();
@Test
public void testNormal() {
TaskDemo taskDemo = new TaskDemo(1000);
TimeOuter timeOuter = new TimeOuter(taskDemo, 5, TimeUnit.SECONDS);
executor.execute(timeOuter);
try {
TimeUnit.SECONDS.sleep(6);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Test
public void testTimeOut() {
TaskDemo taskDemo = new TaskDemo(10000);
TimeOuter timeOuter = new TimeOuter(taskDemo, 5, TimeUnit.SECONDS);
executor.execute(timeOuter);
try {
TimeUnit.SECONDS.sleep(6);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}