Во-первых, убедитесь, что вы храните события в очереди в том порядке, в котором они должны быть выполнены.Это гарантирует, что вам нужно только посмотреть на начало очереди, чтобы увидеть, когда должно быть запланировано следующее событие.Для этого вы можете использовать PriorityQueue
.
Ваш поток для обработки событий будет опрашивать элементы из этой очереди и обрабатывать их.Сделайте так, чтобы он заглянул в головной элемент и выяснил, когда нужно запустить следующее событие.Выберите объект для использования в качестве объекта блокировки и вызовите основной поток Object.wait(long)
для этого объекта, передавая метод количество миллисекунд до тех пор, пока не потребуется запустить следующее событие.
Если приходит новый потокдобавьте его в очередь в соответствующем месте.Если элемент находится в начале очереди, это означает, что поток должен проснуться раньше.Вызовите Object.notifyAll()
для объекта блокировки, чтобы активировать поток обработки.Он увидит, что нечего обрабатывать, и вернется ко сну на соответствующее время.
public class ProcessingQueue extends Thread {
private PriorityQueue<Task> tasks;
private volatile boolean isRunning = true;
public void addTask(Task t) {
synchronized (this.tasks) {
this.tasks.offer(t);
// this call requires synchronization to this.tasks
this.tasks.notifyAll();
}
}
public void shutdown() {
this.isRunning = false;
synchronized (this.tasks) {
this.notifyAll();
}
}
public void run() {
while (this.isRunning) {
synchronized (this.tasks) {
Task t = this.tasks.peek();
// by default, if there are no tasks, this will wake every 60 seconds
long millisToSleep = 60000;
// getExecuteMillis() should return the time, in milliseconds, for execution
if (t != null) millisToSleep = t.getExecuteMillis() - System.currentTimeMillis();
if (millisToSleep > 0) {
try {
// this line requires synchronization to this.tasks
// and the lock is removed while it waits
this.tasks.wait(millisToSleep);
} catch (InterruptedException e) {
}
}
t = this.tasks.poll();
if (t != null) {
t.execute();
}
}
}
}
}