溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

環(huán)形隊(duì)列高效觸發(fā)大量超時(shí)任務(wù)的算法實(shí)現(xiàn)

發(fā)布時(shí)間:2020-07-22 00:22:03 來(lái)源:網(wǎng)絡(luò) 閱讀:17695 作者:zhuwensheng 欄目:軟件技術(shù)

基于環(huán)形隊(duì)列的超時(shí)觸發(fā)算法只需要一個(gè)timer即可實(shí)現(xiàn)批量超時(shí)任務(wù)的觸發(fā),CPU消耗低,效率高。原理介紹,下面是此算法的簡(jiǎn)單實(shí)現(xiàn)。

1,TaskHolder.java

package com.zws.timer;
/**
 * 
 * @author wensh.zhu
 * @date 2018-04-22
 */
public class TaskHolder {
	
	/** 任務(wù)所需等待的圈數(shù),即任務(wù)需要走幾圈**/
	private int cycles;
	private int delays;
	private Runnable task;
	
	public TaskHolder() {}

	public TaskHolder(int cycles, int delays, Runnable task) {
		this.cycles = cycles;
		this.delays = delays;
		this.task = task;
	}
	
	public boolean isTimeOut() {
		return cycles <= 0;
	}
	
	public void cutDown() {
		cycles --;
	}

	public int getCycles() {
		return cycles;
	}

	public void setCycles(int cycles) {
		this.cycles = cycles;
	}

	public int getDelays() {
		return delays;
	}

	public void setDelays(int delays) {
		this.delays = delays;
	}

	public Runnable getTask() {
		return task;
	}

	public void setTask(Runnable task) {
		this.task = task;
	}

	@Override
	public String toString() {
		return "TaskHolder[cycles=" + cycles + ", delays=" + delays + "]";
	}
	
}

2,TimerContext.java

package com.zws.timer;

import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
 * 
 * @author wensh.zhu
 * @date 2018-04-22
 */
public class TimerContext {

	public static final int DEFAULT_TICKS = 60;
	public static final int DEFAULT_TICK_DURATION = 1;
	
	private Map<Integer, Queue<TaskHolder>> taskHolders;
	private volatile int currentTick = 0;
	
	/** tick一圈的長(zhǎng)度 **/
	private int ticks = DEFAULT_TICKS;
	
	/** 每tick一次的時(shí)間間隔,單位:秒**/
	private int tickDuration = DEFAULT_TICK_DURATION;
	
	public TimerContext() {
		init();
	}

	public TimerContext(int ticks, int tickDuration) {
		if (ticks <= 0)
			throw new IllegalArgumentException("ticks must be greater than 0");
		
		if (tickDuration <= 0)
			throw new IllegalArgumentException("tickDuration must be greater than 0");
		
		this.ticks = ticks;
		this.tickDuration = tickDuration;
		init();
	}
	
	private void init() {
		taskHolders = new ConcurrentHashMap<Integer, Queue<TaskHolder>>();
		for (int i = 0; i < ticks; i ++)
			taskHolders.put(i, new ConcurrentLinkedQueue<TaskHolder>());
	}
	
	/**
	 * 添加一個(gè)定時(shí)任務(wù)并計(jì)算需要走的圈數(shù)和落腳的index
	 * @param task
	 * @param delays
	 */
	public void addTask(Runnable task, int delays) {
		if (task == null) 
			throw new NullPointerException("task must not be null");
		
		if (delays <=0) 
			throw new IllegalArgumentException("delays must be greater than 0");
		
		int allSeconds = ticks * tickDuration;
		int cycles = delays / allSeconds;
		int index = ((delays % allSeconds) / tickDuration) + currentTick;
		TaskHolder metaData = new TaskHolder(cycles, delays, task);
		Queue<TaskHolder> tasks = taskHolders.get(index);
		synchronized (tasks) {
			tasks.add(metaData);
		}
	}
	
	public int tick() {
		currentTick = (currentTick + 1) % ticks;
		return currentTick;
	}
	
	public Queue<TaskHolder> getCurrentTasks() {
		return taskHolders.get(currentTick);
	}

	public int getCurrentTick() {
		return currentTick;
	}

	public int getTicks() {
		return ticks;
	}

	public int getTickDuration() {
		return tickDuration;
	}
	
	@Override
	public String toString() {
		return "TimerContext [timers=" + taskHolders + ", ticks=" + ticks + ", tickDuration=" + tickDuration
				+ ", currentTick=" + currentTick + "]";
	}
}

3,TimerScheduler.java

package com.zws.timer;

import java.io.IOException;
import java.util.Iterator;
import java.util.Queue;
import java.util.Timer;
import java.util.TimerTask;
/**
 * 用于判斷定時(shí)器是否到時(shí)、執(zhí)行任務(wù)、維護(hù)定時(shí)器狀態(tài)。
 * @author wensh.zhu
 * @date 2018-04-22
 */
public class TimerScheduler extends TimerTask {
	
	private TimerContext timerContext;
	
	public TimerScheduler() {}

	public TimerScheduler(TimerContext timerContext) {
		this.timerContext = timerContext;
	}
	
	/**
	 * 定時(shí)檢測(cè),如果定時(shí)器觸發(fā)時(shí)間到了就從集合中刪除并執(zhí)行任務(wù),否則圈數(shù)減一。
	 */
	@Override
	public void run() {
		if (timerContext == null) 
			return;
		
		Queue<TaskHolder> tasks = timerContext.getCurrentTasks();
		synchronized (tasks) {
			Iterator<TaskHolder> itor = tasks.iterator();
			while (itor.hasNext()) {
				TaskHolder timer = itor.next();
				if (timer.isTimeOut()) {
					itor.remove();
					new Thread(timer.getTask()).start();
				} else {
					timer.cutDown();
				}
			}
			
		}
		
		timerContext.tick();
	}
	
	public void addTask(Runnable task, int delays) {
		timerContext.addTask(task, delays);
	}

	public TimerContext getTimerContext() {
		return timerContext;
	}

	public void setTimerContext(TimerContext timerContext) {
		this.timerContext = timerContext;
	}
	
	public static void main(String[] args) throws IOException {
		TimerContext context = new TimerContext(60, 1);
		TimerScheduler sheduler = new TimerScheduler(context);
		sheduler.addTask(new Runnable() {
			
			public void run() {
				System.out.println(DateUtils.now());
			}
		}, 60);
		System.out.println(DateUtils.now());
		
		Timer timer = new Timer();
		timer.scheduleAtFixedRate(sheduler, 0, context.getTickDuration() * 1000L);
		
		System.in.read();
	}
	
}

4,DateUtils.java

package com.zws.timer;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
 * 
 * @author wensh.zhu
 * @date 2018-04-22
 */
public class DateUtils {
	public static final String DEFAULT_PATTERN = "yyyy-MM-dd HH:mm:ss";

	public static String now() {
		LocalDateTime time = LocalDateTime.now();
		return time.format(DateTimeFormatter.ofPattern(DEFAULT_PATTERN));
	}
	
	public static String plusSeconds(int seconds) {
		LocalDateTime time = LocalDateTime.now();
		time.plusSeconds(seconds);
		return time.format(DateTimeFormatter.ofPattern(DEFAULT_PATTERN));
	}
}


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI