Java对线程设置任务执行超时限制

3,462 阅读1分钟

基本思路是利用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();
        }
    }
}