00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 package ikayaki.util;
00024
00025 import java.util.concurrent.DelayQueue;
00026 import java.util.concurrent.Delayed;
00027 import java.util.concurrent.Executor;
00028 import java.util.concurrent.TimeUnit;
00029
00040 public class LastExecutor implements Executor {
00041
00045 private int delayMillis;
00046
00051 private boolean execOnlyLast;
00052
00057 private DelayQueue<RunDelayed> queue = new DelayQueue<RunDelayed>();
00058
00063 private Thread workerThread = null;
00064
00068 public LastExecutor() {
00069 this(0, true);
00070 }
00071
00077 public LastExecutor(int delayMillis) {
00078 this(delayMillis, true);
00079 }
00080
00087 public LastExecutor(boolean execOnlyLast) {
00088 this(0, execOnlyLast);
00089 }
00090
00098 public LastExecutor(int delayMillis, boolean execOnlyLast) {
00099 if (delayMillis < 0) {
00100 delayMillis = 0;
00101 }
00102 this.delayMillis = delayMillis;
00103 this.execOnlyLast = execOnlyLast;
00104 }
00105
00109 public synchronized boolean isExecOnlyLast() {
00110 return execOnlyLast;
00111 }
00112
00117 public synchronized void setExecOnlyLast(boolean execOnlyLast) {
00118 this.execOnlyLast = execOnlyLast;
00119 }
00120
00124 public synchronized int getDelayMillis() {
00125 return delayMillis;
00126 }
00127
00131 public synchronized void setDelayMillis(int delayMillis) {
00132 if (delayMillis >= 0) {
00133 this.delayMillis = delayMillis;
00134 }
00135 }
00136
00145 public synchronized void execute(Runnable command) {
00146 if (command == null) {
00147 throw new NullPointerException();
00148 }
00149 if (execOnlyLast) {
00150 queue.clear();
00151 }
00152 queue.offer(new RunDelayed(command, delayMillis));
00153 if (workerThread == null) {
00154 workerThread = new LastExecutorThread();
00155 workerThread.start();
00156 }
00157 }
00158
00165 public synchronized void join() throws InterruptedException {
00166 while (workerThread != null) {
00167 wait();
00168 }
00169 }
00170
00175 public synchronized void clear() {
00176 queue.clear();
00177 if (workerThread != null) {
00178
00179 queue.offer(new RunDelayed(new Runnable() {
00180 public void run() {
00181
00182 }
00183 }, 0));
00184 }
00185 }
00186
00195 private class LastExecutorThread extends Thread {
00196 public void run() {
00197 while (true) {
00198 synchronized (LastExecutor.this) {
00199 if (queue.size() == 0) {
00200 workerThread = null;
00201 LastExecutor.this.notifyAll();
00202 return;
00203 }
00204 }
00205 RunDelayed delayed = null;
00206 try {
00207 delayed = queue.take();
00208 delayed.getRunnable().run();
00209 } catch (Throwable t) {
00210 System.err.println(t.getClass().getSimpleName() + " thrown by "
00211 + delayed.getRunnable().getClass().getName());
00212 t.printStackTrace();
00213 }
00214 }
00215 }
00216 }
00217
00223 private class RunDelayed implements Delayed {
00224
00228 private long expires;
00229
00233 private Runnable runnable;
00234
00241 public RunDelayed(Runnable runnable, int delayMillis) {
00242 this.expires = System.currentTimeMillis() + delayMillis;
00243 this.runnable = runnable;
00244 }
00245
00252 public long getDelay(TimeUnit unit) {
00253 return expires - System.currentTimeMillis();
00254 }
00255
00261 public Runnable getRunnable() {
00262 return runnable;
00263 }
00264
00273 public int compareTo(Delayed delayed) {
00274 return (int) (getDelay(TimeUnit.MILLISECONDS) - delayed.getDelay(TimeUnit.MILLISECONDS));
00275 }
00276 }
00277
00281 public static void main(String[] args) throws InterruptedException {
00282 LastExecutor q = new LastExecutor(200, true);
00283
00284 for (int i = 0; i < 10; i++) {
00285 final int j = i;
00286 q.execute(new Runnable() {
00287 public void run() {
00288 System.out.println("A " + j);
00289 }
00290 });
00291 }
00292
00293 q.join();
00294
00295 for (int i = 0; i < 10; i++) {
00296 final int j = i;
00297 q.execute(new Runnable() {
00298 public void run() {
00299 System.out.println("B " + j);
00300 }
00301 });
00302 Thread.sleep(50 * i);
00303 }
00304
00305
00306
00307 q.execute(new Runnable() {
00308 public void run() {
00309 System.out.println("C");
00310 try {
00311 Thread.sleep(500);
00312 } catch (InterruptedException e) {
00313 e.printStackTrace();
00314 }
00315 throw new NullPointerException();
00316 }
00317 });
00318 Thread.sleep(300);
00319 q.execute(new Runnable() {
00320 public void run() {
00321 System.out.println("D");
00322 }
00323 });
00324 q.join();
00325
00326
00327 System.out.println("1");
00328 q.execute(new Runnable() {
00329 public void run() {
00330 System.out.println("A");
00331 }
00332 });
00333 Thread.sleep(100);
00334 System.out.println("2");
00335 q.clear();
00336 System.out.println("3");
00337 }
00338 }