package com.yanzuoguang.util.helper; import com.yanzuoguang.util.log.Log; import com.yanzuoguang.util.thread.ThreadHelper; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.function.Consumer; /** * 超时监控 * * @author 颜佐光 */ public class YzgTimeout { public static final int TIME_OUT_DEFAULT = 15 * 1000; public static final int TIME_OUT_TIP = 10 * 1000; private static Queue<TimeInfo> queueInfos = null; /** * 超时监控 * * @param cls 日志类 * @param message 消息 * @param runnable 运行函数 */ public static void timeOut(Class<?> cls, String message, Runnable runnable) { timeOut(cls, message, runnable, null); } /** * 超时监控 * * @param cls 日志类 * @param message 消息 * @param runnable 运行函数 */ public static void timeOut(Class<?> cls, String message, Runnable runnable, Consumer<Long> consumer) { timeHeart(TIME_OUT_DEFAULT, TIME_OUT_TIP, runnable, (time) -> { Log.error(cls, "%s超时,已经执行%d豪秒,正在等待执行完成", message, time); if (consumer != null) { consumer.accept(time); } }); } /** * 超时监控 * * @param runnable 运行函数 * @param heart 心跳函数 */ public static void timeHeart(Runnable runnable, YzgTimeoutHeart heart) { timeHeart(TIME_OUT_DEFAULT, TIME_OUT_TIP, runnable, heart); } /** * 超时监控 * * @param tipOutDefault 默认超时时间 * @param timeOutTip 超时心跳间隔 * @param runnable 运行函数 * @param heart 心跳函数 */ public static void timeHeart(int tipOutDefault, int timeOutTip, Runnable runnable, YzgTimeoutHeart heart) { TimeInfo timeInfo = getTimeInfo(tipOutDefault, timeOutTip, heart); try { runnable.run(); } finally { timeInfo.setRun(true); } } private static TimeInfo getTimeInfo(int tipOutDefault, int timeOutTip, YzgTimeoutHeart heart) { init(); TimeInfo timeInfo = new TimeInfo(tipOutDefault, timeOutTip, heart); synchronized (queueInfos) { queueInfos.add(timeInfo); } return timeInfo; } private static void init() { if (queueInfos != null) { return; } synchronized (YzgTimeout.class) { if (queueInfos != null) { return; } queueInfos = new ConcurrentLinkedQueue<>(); ThreadHelper.runThread(() -> { while (true) { try { runItem(); } catch (Exception ex) { ex.printStackTrace(); } ThreadHelper.sleep(200); } }); } } private static void runItem() { int size; synchronized (queueInfos) { size = queueInfos.size(); } for (int i = 0; i < size; i++) { TimeInfo poll; synchronized (queueInfos) { poll = queueInfos.poll(); } if (poll == null) { return; } long end = System.currentTimeMillis(); long time = end - poll.getStart(); if (time > poll.getTimeMax()) { try { poll.setTimeMax(poll.getTimeMax() + poll.getTimeOutTip()); ThreadHelper.runThread(() -> poll.getHeart().heart(time)); } catch (Exception ex) { ex.printStackTrace(); } } if (!poll.isRun()) { synchronized (queueInfos) { queueInfos.add(poll); } } } } } class TimeInfo { private int timeOutDefault; private int timeOutTip; private YzgTimeoutHeart heart; private boolean run; private long start; private int timeMax; public TimeInfo(int timeOutDefault, int timeOutTip, YzgTimeoutHeart heart) { this.timeOutDefault = timeOutDefault; this.timeOutTip = timeOutTip; this.heart = heart; this.timeMax = timeOutDefault; this.start = System.currentTimeMillis(); } public int getTimeOutDefault() { return timeOutDefault; } public void setTimeOutDefault(int timeOutDefault) { this.timeOutDefault = timeOutDefault; } public int getTimeOutTip() { return timeOutTip; } public void setTimeOutTip(int timeOutTip) { this.timeOutTip = timeOutTip; } public YzgTimeoutHeart getHeart() { return heart; } public void setHeart(YzgTimeoutHeart heart) { this.heart = heart; } public boolean isRun() { return run; } public void setRun(boolean run) { this.run = run; } public long getStart() { return start; } public void setStart(long start) { this.start = start; } public int getTimeMax() { return timeMax; } public void setTimeMax(int timeMax) { this.timeMax = timeMax; } }