写一个定时自检

有一个后台程序需要这么一个功能:
需要知道自己什么时候进入稳定状态

我原来用一种沙雕方式实现的,即开一个线程让一个计数器定时自增,自增到某个数即表示已经进入稳定状态,如果中间有打破这种状态的操作,那么就让计数器重置为0:

	public static AtomicInteger STABLE_TIMER = new AtomicInteger(0);
	
		taskExecutors.execute(new Runnable() {
    
    
			@Override
			public void run() {
    
    
				while (true) {
    
    
					try {
    
    
						TimeUnit.SECONDS.sleep(1);
						if (STABLE_TIMER.getAndIncrement() == LC.STABLE_MIN_TIME) {
    
    
							L.i(Thread.currentThread().getName() + "|进入稳定状态,报告自身状态");
							//TODO 进入稳定状态需要做的操作
						}
					} catch (InterruptedException e) {
    
    
						e.printStackTrace();
						STABLE_TIMER.decrementAndGet();
					}
				}
			}
		});

虽然勉强达到了效果,但实在是…
太丑了

后来想了想,其实可以找到一些类比场景,比如轮询,比如心跳;

再仔细想想,原来看过的netty心跳源码中有一段和这个需求非常相似,比如读取超时的判断就依赖一个ReaderIdleTimeoutTask

    ScheduledFuture<?> schedule(ChannelHandlerContext ctx, Runnable task, long delay, TimeUnit unit) {
    
    
        return ctx.executor().schedule(task, delay, unit);
    }

    private final class ReaderIdleTimeoutTask extends AbstractIdleTask {
    
    

        ReaderIdleTimeoutTask(ChannelHandlerContext ctx) {
    
    
            super(ctx);
        }

        @Override
        protected void run(ChannelHandlerContext ctx) {
    
    
            long nextDelay = readerIdleTimeNanos;
            if (!reading) {
    
    
                nextDelay -= ticksInNanos() - lastReadTime;
            }

            if (nextDelay <= 0) {
    
    
                // Reader is idle - set a new timeout and notify the callback.
                readerIdleTimeout = schedule(ctx, this, readerIdleTimeNanos, TimeUnit.NANOSECONDS);

                boolean first = firstReaderIdleEvent;
                firstReaderIdleEvent = false;

                try {
    
    
                    IdleStateEvent event = newIdleStateEvent(IdleState.READER_IDLE, first);        
                    channelIdle(ctx, event);
                } catch (Throwable t) {
    
    
                    ctx.fireExceptionCaught(t);
                }
            } else {
    
    
                // Read occurred before the timeout - set a new timeout with shorter delay.
                readerIdleTimeout = schedule(ctx, this, nextDelay, TimeUnit.NANOSECONDS);
            }
        }
    }

其中channelIdle方法就相当于进入了一种判定状态,在这里当然是判定为超时了。

所以Netty的心跳就是这样:定时自检是否已经达到一种“超时状态“,如果当前没有,那么就上次的时间进行计算,再决定下一次自检的时间。

那么可以直接仿写一个task,整一个工具类出来:

public class StableStateHolder {
    
    

	private static class Holder {
    
    
		static StableStateHolder INSTANCE = new StableStateHolder();
	}

	public static StableStateHolder get() {
    
    
		return Holder.INSTANCE;
	}

	private ScheduledExecutorService stableTimer;

	private ScheduledFuture<?> stableTimeout;

	private static final long DELAY = 10 * 1000;
	private static final long DELAY_LONG = 20 * 1000;

	private long currentTimeMills;

	private StableStateHolder() {
    
    
		stableTimer = new ScheduledThreadPoolExecutor(1);
		stableTimeout = schedule(new StableTimeoutTask(), DELAY_LONG, TimeUnit.MILLISECONDS);
		currentTimeMills = System.currentTimeMillis();
	}

	public void tick() {
    
    
		currentTimeMills = System.currentTimeMillis();
	}

	private ScheduledFuture<?> schedule(Runnable task, long delay, TimeUnit unit) {
    
    
		return stableTimer.schedule(task, delay, unit);
	}

	private final class StableTimeoutTask implements Runnable {
    
    

		@Override
		public void run() {
    
    
			long prevDelay = System.currentTimeMillis() - currentTimeMills;
			if (prevDelay > DELAY) {
    
    
				//TODO 进入判定状态
				stableTimeout = schedule(this, DELAY, TimeUnit.MILLISECONDS);
			} else {
    
    
				stableTimeout = schedule(this, DELAY - prevDelay, TimeUnit.MILLISECONDS);
			}
			L.w("活跃线程数:" + Thread.activeCount());
		}
	}
}

这样就好看多了,虽然还是有点沙雕。哈哈哈哈。

猜你喜欢

转载自blog.csdn.net/ifmylove2011/article/details/105976768
今日推荐