1 18 package org.apache.batik.util; 19 20 import java.util.Iterator ; 21 22 29 public class RunnableQueue implements Runnable { 30 31 34 public static class RunnableQueueState extends Object { 35 final String value; 36 private RunnableQueueState(String value) { 37 this.value = value.intern(); } 38 public String getValue() { return value; } 39 public String toString() { 40 return "[RunnableQueueState: " + value + "]"; } 41 } 42 43 46 public static final RunnableQueueState RUNNING 47 = new RunnableQueueState("Running"); 48 49 53 public static final RunnableQueueState SUSPENDING 54 = new RunnableQueueState("Suspending"); 55 56 60 public static final RunnableQueueState SUSPENDED 61 = new RunnableQueueState("Suspended"); 62 63 66 protected RunnableQueueState state; 67 68 72 protected Object stateLock = new Object (); 73 74 78 protected boolean wasResumed; 79 80 84 protected DoublyLinkedList list = new DoublyLinkedList(); 85 86 90 protected int preemptCount = 0; 91 92 95 protected RunHandler runHandler; 96 97 100 protected HaltingThread runnableQueueThread; 101 102 107 public static RunnableQueue createRunnableQueue() { 108 RunnableQueue result = new RunnableQueue(); 109 synchronized (result) { 110 HaltingThread ht = new HaltingThread 111 (result, "RunnableQueue-" + threadCount++); 112 ht.setDaemon(true); 113 ht.start(); 114 while (result.getThread() == null) { 115 try { 116 result.wait(); 117 } catch (InterruptedException ie) { 118 } 119 } 120 } 121 return result; 122 } 123 private static int threadCount; 124 125 128 public void run() { 129 synchronized (this) { 130 runnableQueueThread = (HaltingThread)Thread.currentThread(); 131 notify(); 134 } 135 136 Link l; 137 Runnable rable; 138 try { 139 while (!HaltingThread.hasBeenHalted()) { 140 141 synchronized (stateLock) { 143 if (state == RUNNING) { 144 145 if (wasResumed) { 146 wasResumed = false; 147 executionResumed(); 148 } 149 } else { 150 151 while (state != RUNNING) { 152 state = SUSPENDED; 153 154 stateLock.notifyAll(); 157 158 executionSuspended(); 159 160 try { 162 stateLock.wait(); 163 } catch(InterruptedException ie) { } 164 } 165 166 wasResumed = false; 167 executionResumed(); 168 } 169 } 170 171 178 synchronized (list) { 179 if (state == SUSPENDING) 180 continue; 181 l = (Link)list.pop(); 182 if (preemptCount != 0) preemptCount--; 183 if (l == null) { 184 try { 186 list.wait(); 187 } catch (InterruptedException ie) { 188 } 190 continue; } 192 193 rable = l.runnable; 194 } 195 196 runnableStart(rable); 197 198 try { 199 rable.run(); 200 } catch (ThreadDeath td) { 201 throw td; 203 } catch (Throwable t) { 204 t.printStackTrace(); 207 } 208 l.unlock(); 209 runnableInvoked(rable); 210 } 211 } catch (InterruptedException e) { 212 } finally { 213 synchronized (this) { 214 runnableQueueThread = null; 215 } 216 } 217 } 218 219 224 public HaltingThread getThread() { 225 return runnableQueueThread; 226 } 227 228 234 public void invokeLater(Runnable r) { 235 if (runnableQueueThread == null) { 236 throw new IllegalStateException 237 ("RunnableQueue not started or has exited"); 238 } 239 synchronized (list) { 240 list.push(new Link(r)); 241 list.notify(); 242 } 243 } 244 245 253 public void invokeAndWait(Runnable r) throws InterruptedException { 254 if (runnableQueueThread == null) { 255 throw new IllegalStateException 256 ("RunnableQueue not started or has exited"); 257 } 258 if (runnableQueueThread == Thread.currentThread()) { 259 throw new IllegalStateException 260 ("Cannot be called from the RunnableQueue thread"); 261 } 262 263 LockableLink l = new LockableLink(r); 264 synchronized (list) { 265 list.push(l); 266 list.notify(); 267 } 268 l.lock(); 269 } 270 271 272 280 public void preemptLater(Runnable r) { 281 if (runnableQueueThread == null) { 282 throw new IllegalStateException 283 ("RunnableQueue not started or has exited"); 284 } 285 synchronized (list) { 286 list.add(preemptCount, new Link(r)); 287 preemptCount++; 288 list.notify(); 289 } 290 } 291 292 302 public void preemptAndWait(Runnable r) throws InterruptedException { 303 if (runnableQueueThread == null) { 304 throw new IllegalStateException 305 ("RunnableQueue not started or has exited"); 306 } 307 if (runnableQueueThread == Thread.currentThread()) { 308 throw new IllegalStateException 309 ("Cannot be called from the RunnableQueue thread"); 310 } 311 312 LockableLink l = new LockableLink(r); 313 synchronized (list) { 314 list.add(preemptCount, l); 315 preemptCount++; 316 list.notify(); 317 } 318 l.lock(); 319 } 320 321 public RunnableQueueState getQueueState() { 322 synchronized (stateLock) { 323 return state; 324 } 325 } 326 327 337 public void suspendExecution(boolean waitTillSuspended) { 338 if (runnableQueueThread == null) { 339 throw new IllegalStateException 340 ("RunnableQueue not started or has exited"); 341 } 342 synchronized (stateLock) { 344 wasResumed = false; 345 346 if (state == SUSPENDED) { 347 stateLock.notifyAll(); 350 return; 351 } 352 353 if (state == RUNNING) { 354 state = SUSPENDING; 355 synchronized (list) { 356 list.notify(); 360 } 361 } 362 363 if (waitTillSuspended) { 364 while (state == SUSPENDING) { 365 try { 366 stateLock.wait(); 367 } catch(InterruptedException ie) { } 368 } 369 } 370 } 371 } 372 373 377 public void resumeExecution() { 378 if (runnableQueueThread == null) { 380 throw new IllegalStateException 381 ("RunnableQueue not started or has exited"); 382 } 383 384 synchronized (stateLock) { 385 wasResumed = true; 386 387 if (state != RUNNING) { 388 state = RUNNING; 389 stateLock.notifyAll(); } 391 } 392 } 393 394 398 public Object getIteratorLock() { 399 return list; 400 } 401 402 405 public Iterator iterator() { 406 return new Iterator () { 407 Link head = (Link)list.getHead(); 408 Link link; 409 public boolean hasNext() { 410 if (head == null) { 411 return false; 412 } 413 if (link == null) { 414 return true; 415 } 416 return link != head; 417 } 418 public Object next() { 419 if (head == null || head == link) { 420 throw new java.util.NoSuchElementException (); 421 } 422 if (link == null) { 423 link = (Link)head.getNext(); 424 return head.runnable; 425 } 426 Object result = link.runnable; 427 link = (Link)link.getNext(); 428 return result; 429 } 430 public void remove() { 431 throw new UnsupportedOperationException (); 432 } 433 }; 434 } 435 436 439 public synchronized void setRunHandler(RunHandler rh) { 440 runHandler = rh; 441 } 442 443 446 public synchronized RunHandler getRunHandler() { 447 return runHandler; 448 } 449 450 454 protected synchronized void executionSuspended() { 455 if (runHandler != null) { 457 runHandler.executionSuspended(this); 458 } 459 } 460 461 465 protected synchronized void executionResumed() { 466 if (runHandler != null) { 468 runHandler.executionResumed(this); 469 } 470 } 471 472 477 protected synchronized void runnableStart(Runnable rable ) { 478 if (runHandler != null) { 479 runHandler.runnableStart(this, rable); 480 } 481 } 482 483 488 protected synchronized void runnableInvoked(Runnable rable ) { 489 if (runHandler != null) { 490 runHandler.runnableInvoked(this, rable); 491 } 492 } 493 494 498 public interface RunHandler { 499 500 503 void runnableStart(RunnableQueue rq, Runnable r); 504 505 509 void runnableInvoked(RunnableQueue rq, Runnable r); 510 511 514 void executionSuspended(RunnableQueue rq); 515 516 519 void executionResumed(RunnableQueue rq); 520 } 521 522 526 public static class RunHandlerAdapter implements RunHandler { 527 528 531 public void runnableStart(RunnableQueue rq, Runnable r) { } 532 533 537 public void runnableInvoked(RunnableQueue rq, Runnable r) { } 538 539 542 public void executionSuspended(RunnableQueue rq) { } 543 544 547 public void executionResumed(RunnableQueue rq) { } 548 } 549 550 553 protected static class Link extends DoublyLinkedList.Node { 554 555 558 public Runnable runnable; 559 560 563 public Link(Runnable r) { 564 runnable = r; 565 } 566 567 571 public void unlock() throws InterruptedException { return; } 572 } 573 574 577 protected static class LockableLink extends Link { 578 579 582 protected boolean locked; 583 584 587 public LockableLink(Runnable r) { 588 super(r); 589 } 590 591 594 public boolean isLocked() { 595 return locked; 596 } 597 598 601 public synchronized void lock() throws InterruptedException { 602 locked = true; 603 notify(); 604 wait(); 605 } 606 607 610 public synchronized void unlock() throws InterruptedException { 611 while (!locked) { 612 wait(); 614 } 615 notify(); 617 } 618 } 619 } 620 | Popular Tags |