Luo Hao

Java线程定时得到结果退出示例

rehoni / 2020-11-24


大致需求

定时每几秒调用一次rest接口,如果接口响应成功则退出线程,如果接口响应失败,则继续调用直至成功。

做了一个简单的线程任务。简单来说是一个异步的调用方式。目前采用的方式是设置一个flag,作为判断rest接口是否调用成功的结果标志位,接口调用不成功则线程死循环;接口调用成功则线程不进入while,退出。

public static void main(String[] args) {
    // 线程沉睡时间,每3秒试图调用一次接口插入到告警表
    final long timeInterval = 3000;
    AtomicBoolean flag = new AtomicBoolean(false);
    Thread thread = new Thread(() -> {
        while (!flag.get()) {
            flag.set(testFlag());
            try {
                Thread.sleep(timeInterval);
            } catch (InterruptedException e) {
                log.info("thread sleep interrupted");
            }
        }
    });
    thread.start();
}

private static boolean testFlag() {
    int code = 500;
    boolean fl = false;
    try {
        if (code == 500) {
            throw new NullPointerException();
        } else if (code == 200) {
            log.info("code = 200,存入数据库");
            fl = true;
        }
    } catch (Exception e) {
        log.info("未获得code");
        return false;
    }
    return fl;
}
Connected to the target VM, address: '127.0.0.1:51619', transport: 'socket'
15:38:56.445 [Thread-0] INFO com.nrec.pcs9000.app.task.RobotLinkageTask - 未获得code
15:38:59.450 [Thread-0] INFO com.nrec.pcs9000.app.task.RobotLinkageTask - 未获得code
15:39:02.451 [Thread-0] INFO com.nrec.pcs9000.app.task.RobotLinkageTask - 未获得code
15:39:05.452 [Thread-0] INFO com.nrec.pcs9000.app.task.RobotLinkageTask - 未获得code
15:39:08.453 [Thread-0] INFO com.nrec.pcs9000.app.task.RobotLinkageTask - 未获得code
15:39:25.722 [Thread-0] INFO com.nrec.pcs9000.app.task.RobotLinkageTask - code = 200,存入数据库
Disconnected from the target VM, address: '127.0.0.1:51619', transport: 'socket'

需求升级

在原有需求上考量,如果接口持续调用失败,那新开的线程则一直不会退出。一段时间内产生的线程要是足够多,说不定导致所有的线程不会退出,JVM宕机。因此在原有的基础上加一个固定的超时需求。

定时每几秒调用一次rest接口,如果接口响应成功则退出线程,如果接口响应失败,则继续调用直至成功。如果接口响应一直失败,则在固定的时间内超时退出。

// 线程沉睡时间,每6秒试图调用一次接口插入到告警表
ExecutorService executor = Executors.newSingleThreadExecutor();
final long timeInterval = 6000;
AtomicBoolean flag = new AtomicBoolean(false);
Future<Boolean> future = executor.submit(() -> {
    while (!flag.get()) {
        flag.set(getAndInsertTaskPatrolledId(headerParameters, taskCode, stationCode));
        try {
            Thread.sleep(timeInterval);
        } catch (InterruptedException e) {
            log.info("线程中断,退出");
            return false;
        }
    }
    // 注意这里也是false,退出while之后线程也是结束的
    return false;
});
try {
    log.info("开始获取机器人任务运行状态");
    // 10分钟超时时间
    future.get(600, TimeUnit.SECONDS);
    log.info("获取机器人任务运行状态成功,已存入数据库!");
} catch (TimeoutException e) {
    future.cancel(true);
    log.info("线程超时结束!");
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
}
executor.shutdownNow();