为程序块增加超时限制功能(修正2)

一、背景

在做产品时发现在某一逻辑中需要加入超时的限制,但原有程序块并不支持也不能修改。所以我需要在外部包装一层,加入超时逻辑。


二、分析(修正2)

想控制一段代码段的执行,我们可以采用开启新线程(Thread)的方式来控制。判断线程超时有多种方式,为了降低编码量我采用 CountDownLatch.await(...) 方法,将异步的执行线程转换为同步方式。

逻辑过程:

a、将需要限制的程序段放入新创建的内嵌线程(Thread)执行
b、Thread 构造时,设置 new CountDownLatch(1);
c、启动内嵌线程 Thread.start()
d、CountDownLatch.await 等待内嵌线程中 latch 被 countDown()
e1、内嵌线程逻辑在 await 超时时间内完成,调用 countDown 释放 await
    f、await 返回 true,说明执行没有超时
e2、
内嵌线程逻辑没有在 await 超时时间内完成(超时),await 会返回 false
    g、await 返回 false,说明执行超时


三、限时程序辅助类(修正2)

TimeoutExecution 超时限制执行辅助类。为了获取内嵌执行代码段的返回值与异常,加入了 result 与 exception 成员变量。

package org.noahx.stimeout;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * 超时限制执行辅助类(线程不安全,使用时请创建新实例)
 * 

* Created by noah on 6/10/14. */ public abstract class TimeoutExecution { private Logger logger = LoggerFactory.getLogger(this.getClass()); private volatile Exception exception; private CountDownLatch latch; private T result; /** * 需要实现的具体执行内容 * * @return 返回值 * @throws Exception 异常 */ protected abstract T execute() throws Exception; /** * 超时限制执行 * * @param timeout 超时时间数值 * @param unit 超时时间单位 * @return true,没有超时正常返回,false 超时 */ public boolean execute(int timeout, TimeUnit unit) { result = null; //清楚上次数据 latch = new CountDownLatch(1); InnerThread innerThread = new InnerThread(); //初始化内部执行线程 innerThread.start(); boolean isNotTimeout = true; try { isNotTimeout = latch.await(timeout, unit); //等待执行完毕 } catch (InterruptedException e) { logger.error(e.getMessage(), e); } if (!isNotTimeout) { innerThread.interrupt(); //终止连接线程 } return isNotTimeout; } private class InnerThread extends Thread { @Override public void run() { try { result = execute(); //存储执行结果 } catch (Exception e) { exception = e; //存储执行异常 } finally { latch.countDown(); //释放等待 } } } public T getResult() { return result; } public Exception getException() { return exception; } }


[修正1]:TimeoutExecution2 超时限制执行辅助类(使用 FutureTask,效果一样)。

package org.noahx.stimeout;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;

/**
 * 超时限制执行辅助类(线程不安全,使用时请创建新实例)
 * 

* Created by noah on 6/10/14. */ public abstract class TimeoutExecution2 implements Callable { private Logger logger = LoggerFactory.getLogger(this.getClass()); private volatile Exception exception; private T result; /** * 需要实现的具体执行内容 * * @return 返回值 * @throws Exception 异常 */ protected abstract T execute() throws Exception; /** * 超时限制执行 * * @param timeout 超时时间数值 * @param unit 超时时间单位 * @return true,没有超时正常返回,false 超时 */ public boolean execute(int timeout, TimeUnit unit) { result = null; //清楚上次数据 FutureTask futureTask = new FutureTask(this); boolean isNotTimeout = true; try { new Thread(futureTask).start(); result = futureTask.get(timeout, unit); } catch (InterruptedException e) { exception = e; } catch (ExecutionException e) { exception = (Exception) e.getCause(); } catch (TimeoutException e) { isNotTimeout = false; } finally{ // ------[修正2]+ futureTask.cancel(true); // ------[修正2]+ } return isNotTimeout; } @Override public T call() throws Exception { return execute(); } public T getResult() { return result; } public Exception getException() { return exception; } }


四、使用辅助类(样例)

1、TimeoutExample 样例类

具体详见注释,模拟了4种执行情况。

package org.noahx.stimeout;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.SimpleLogger;

import java.util.concurrent.TimeUnit;

/**
 * Created by noah on 6/10/14.
 */
public class TimeoutExample {

    static {
        System.setProperty(SimpleLogger.SHOW_DATE_TIME_KEY,"true");
    }

    private static Logger logger = LoggerFactory.getLogger(TimeoutExample.class);

    public static void main(String[] args) {



        logger.info("1:---------------[正常执行不超时]");
        TimeoutExecution timeoutExecution1 = new TimeoutExecution() { //设置5s 超时
            @Override
            protected Void execute() throws Exception {
                logger.info("exe:1");
                return null;
            }
        };
        boolean execute1 = timeoutExecution1.execute(5, TimeUnit.SECONDS);
        printResult(execute1, timeoutExecution1); //设置5s 超时

        logger.info("2:---------------[执行超时]");
        TimeoutExecution timeoutExecution2 = new TimeoutExecution() {
            @Override
            protected Void execute() throws Exception {
                logger.info("exe:2");
                Thread.sleep(10000); //模拟执行消耗 10s
                return null;
            }
        };
        boolean execute2 = timeoutExecution2.execute(5, TimeUnit.SECONDS);
        printResult(execute2, timeoutExecution2); //设置5s 超时

        logger.info("3:---------------[有返回值]");
        TimeoutExecution timeoutExecution3 = new TimeoutExecution() {
            @Override
            protected Integer execute() throws Exception {
                logger.info("exe:3");
                Thread.sleep(1000); //模拟执行消耗 1s
                return 123;
            }
        };
        boolean execute3 = timeoutExecution3.execute(5, TimeUnit.SECONDS);
        printResult(execute3, timeoutExecution3);

        logger.info("4:---------------[没有超时,但执行有异常]");
        TimeoutExecution timeoutExecution4 = new TimeoutExecution() {
            @Override
            protected Integer execute() throws Exception {
                logger.info("exe:4");
                Thread.sleep(1000); //模拟执行消耗 1s
                if (true) {
                    throw new RuntimeException("模拟异常");
                }
                return 123;
            }
        };
        boolean execute4 = timeoutExecution4.execute(5, TimeUnit.SECONDS);
        printResult(execute4, timeoutExecution4);
    }

    private static void printResult(boolean isNotTimeout, TimeoutExecution execution) {
        if (isNotTimeout) {
            logger.info("Ok!!");
            logger.info("result=" + execution.getResult());
            logger.info("e=" + execution.getException());
        } else {
            logger.info("Timeout!!");
            logger.info("result=" + execution.getResult());
            logger.info("e=" + execution.getException());
        }

    }
}


2、执行输出结果

9 [main] INFO org.noahx.stimeout.TimeoutExample - 1:---------------[正常执行不超时]
16 [Thread-0] INFO org.noahx.stimeout.TimeoutExample - exe:1
17 [main] INFO org.noahx.stimeout.TimeoutExample - Ok!!
17 [main] INFO org.noahx.stimeout.TimeoutExample - result=null
17 [main] INFO org.noahx.stimeout.TimeoutExample - e=null
17 [main] INFO org.noahx.stimeout.TimeoutExample - 2:---------------[执行超时]
20 [Thread-1] INFO org.noahx.stimeout.TimeoutExample - exe:2
5020 [main] INFO org.noahx.stimeout.TimeoutExample - Timeout!!
5020 [main] INFO org.noahx.stimeout.TimeoutExample - result=null
5020 [main] INFO org.noahx.stimeout.TimeoutExample - e=null
5020 [main] INFO org.noahx.stimeout.TimeoutExample - 3:---------------[有返回值]
5025 [Thread-2] INFO org.noahx.stimeout.TimeoutExample - exe:3
6026 [main] INFO org.noahx.stimeout.TimeoutExample - Ok!!
6026 [main] INFO org.noahx.stimeout.TimeoutExample - result=123
6026 [main] INFO org.noahx.stimeout.TimeoutExample - e=null
6026 [main] INFO org.noahx.stimeout.TimeoutExample - 4:---------------[没有超时,但执行有异常]
6032 [Thread-3] INFO org.noahx.stimeout.TimeoutExample - exe:4
7032 [main] INFO org.noahx.stimeout.TimeoutExample - Ok!!
7032 [main] INFO org.noahx.stimeout.TimeoutExample - result=null
7032 [main] INFO org.noahx.stimeout.TimeoutExample - e=java.lang.RuntimeException: 模拟异常


五、源码下载

http://1drv.ms/1zHq3Oe

转载于:https://my.oschina.net/noahxiao/blog/291426

你可能感兴趣的:(为程序块增加超时限制功能(修正2))