まず、実行する必要がある順序でイベントをキューに保持してください。これにより、キューの先頭を見て、次のイベントのスケジュールを確認するだけで済みます。これにはPriorityQueue
を使用できます。
イベントを処理するスレッドは、このキューからアイテムをポーリングして処理します。ヘッドアイテムを覗いて、次のイベントをいつ実行する必要があるかを確認します。ロッキングオブジェクトとして使用するオブジェクトを選択し、そのオブジェクトにメインスレッドのObject.wait(long)
を呼び出し、メソッドに次のイベントを実行するまでのミリ秒数を渡します。
新しいスレッドが入った場合は、適切な場所のキューに追加します。アイテムがキューの先頭にある場合は、スレッドが早く起きる必要があることを意味します。 lockオブジェクトの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();
}
}
}
}
}
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/DelayQueue.html Java遅延キューを参照してください。時間ベースのタスクキューには非常に適しています。ここにソースコードがありますhttp://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/concurrent/DelayQueue.java#DelayQueue.take%28%29 – Anshul