package org.archstudio.sysutils; /** * This is a utility base Thread class for executing an activity once after a given delay where additional requests to * execute the activity during the delay period reset the delay. This is useful, for example, in dealing with cases * where each of a burst of events would cause a computationally-intensive operation that is only dependent upon the * last event. So, let's say we get 1000 events inside two seconds. Each of them should trigger the recomputation, but * we don't want to actually recompute 1000 times when once at the end would be enough. This allows us to ignore all but * the last request, and, after a short delay, perform recomputation once. */ public class DelayedExecuteOnceThread extends Thread { protected boolean needsExecution = false; protected boolean shouldTerminate = false; protected boolean waitingForExecution = false; protected int delay; protected Runnable r; public DelayedExecuteOnceThread(int delay, Runnable r) { this(delay, r, false, false); } public DelayedExecuteOnceThread(int delay, Runnable r, boolean daemon, boolean start) { this.delay = delay; this.r = r; setDaemon(daemon); if (start) { start(); } } public synchronized void execute() { needsExecution = true; this.notifyAll(); } public synchronized void executeAndWait() { waitingForExecution = true; execute(); while (waitingForExecution) { try { this.wait(); } catch (InterruptedException ie2) { } } } public synchronized void terminate() { shouldTerminate = true; this.notifyAll(); } @Override public void run() { while (true) { boolean doExecution = false; synchronized (this) { while (!needsExecution && !shouldTerminate) { try { this.wait(); } catch (InterruptedException ie) { } } while (needsExecution && !shouldTerminate) { needsExecution = false; doExecution = true; if (!waitingForExecution) { try { this.wait(delay); } catch (InterruptedException ie2) { } } } } if (shouldTerminate) { return; } if (doExecution) { r.run(); } synchronized (this) { if (waitingForExecution) { waitingForExecution = false; this.notifyAll(); } } } } }