Lines 63-68
Link Here
|
63 |
* <CODE>RequestProcessor</CODE> instance with limited throughput (probably |
63 |
* <CODE>RequestProcessor</CODE> instance with limited throughput (probably |
64 |
* set to 1), the IDE would try to run all your requests in parallel otherwise. |
64 |
* set to 1), the IDE would try to run all your requests in parallel otherwise. |
65 |
* |
65 |
* |
|
|
66 |
* <P> |
67 |
* Since version 4.6 there is a support for interruption of long running tasks. |
68 |
* There always was a way how to cancel not yet running task using {@link RequestProcessor.Task#cancel } |
69 |
* but if the task was already running, one was out of luck. Since version 4.6 |
70 |
* the thread running the task is interrupted and the Runnable can check for that |
71 |
* and terminate its execution sooner. In the runnable one shall check for |
72 |
* thread interruption (done from {@link RequestProcessor.Task#cancel }) and |
73 |
* if true, return immediatelly as in this example: |
74 |
* <PRE> |
75 |
* public void run () { |
76 |
* while (veryLongTimeLook) { |
77 |
* doAPieceOfIt (); |
78 |
* |
79 |
* if (Thread.interrupted ()) return; |
80 |
* } |
81 |
* } |
82 |
* </PRE> |
83 |
* |
66 |
* @author Petr Nejedly, Jaroslav Tulach |
84 |
* @author Petr Nejedly, Jaroslav Tulach |
67 |
*/ |
85 |
*/ |
68 |
public final class RequestProcessor { |
86 |
public final class RequestProcessor { |
Lines 356-362
Link Here
|
356 |
final Item localItem; |
374 |
final Item localItem; |
357 |
synchronized (processorLock) { |
375 |
synchronized (processorLock) { |
358 |
notifyRunning(); |
376 |
notifyRunning(); |
359 |
if (item != null) item.clear(); |
377 |
if (item != null) item.clear(null); |
360 |
item = new Item(this, RequestProcessor.this); |
378 |
item = new Item(this, RequestProcessor.this); |
361 |
localItem = item; |
379 |
localItem = item; |
362 |
} |
380 |
} |
Lines 381-387
Link Here
|
381 |
*/ |
399 |
*/ |
382 |
public boolean cancel () { |
400 |
public boolean cancel () { |
383 |
synchronized (processorLock) { |
401 |
synchronized (processorLock) { |
384 |
boolean success = (item == null) ? false : item.clear(); |
402 |
boolean success; |
|
|
403 |
if (item == null) { |
404 |
success = false; |
405 |
} else { |
406 |
Processor p = item.getProcessor(); |
407 |
success = item.clear(null); |
408 |
if (p != null) { |
409 |
p.interruptTask (this); |
410 |
} |
411 |
} |
385 |
if (success) notifyFinished(); // mark it as finished |
412 |
if (success) notifyFinished(); // mark it as finished |
386 |
return success; |
413 |
return success; |
387 |
} |
414 |
} |
Lines 422-428
Link Here
|
422 |
synchronized (processorLock) { |
449 |
synchronized (processorLock) { |
423 |
// correct line: toRun = (item == null) ? !isFinished (): (item.clear() && !isFinished ()); |
450 |
// correct line: toRun = (item == null) ? !isFinished (): (item.clear() && !isFinished ()); |
424 |
// the same: toRun = !isFinished () && (item == null ? true : item.clear ()); |
451 |
// the same: toRun = !isFinished () && (item == null ? true : item.clear ()); |
425 |
toRun = !isFinished () && (item == null || item.clear ()); |
452 |
toRun = !isFinished () && (item == null || item.clear (null)); |
426 |
} |
453 |
} |
427 |
|
454 |
|
428 |
if (toRun) { //System.err.println(" ## running it synchronously"); |
455 |
if (toRun) { //System.err.println(" ## running it synchronously"); |
Lines 494-512
Link Here
|
494 |
} |
521 |
} |
495 |
} |
522 |
} |
496 |
|
523 |
|
|
|
524 |
/** Called under the processorLock */ |
497 |
Task askForWork (Processor worker) { |
525 |
Task askForWork (Processor worker) { |
498 |
synchronized (processorLock) { |
526 |
if (stopped || queue.isEmpty()) { // no more work in this burst, return him |
499 |
if (stopped || queue.isEmpty()) { // no more work in this burst, return him |
527 |
processors.remove(worker); |
500 |
processors.remove(worker); |
528 |
Processor.put(worker); |
501 |
Processor.put(worker); |
529 |
running--; |
502 |
running--; |
530 |
return null; |
503 |
return null; |
531 |
} else { // we have some work for the worker, pass it |
504 |
} else { // we have some work for the worker, pass it |
532 |
Item i = (Item) queue.remove(0); |
505 |
Item i = (Item) queue.remove(0); |
533 |
Task t = i.getTask (); |
506 |
Task t = i.getTask (); |
534 |
i.clear (worker); |
507 |
i.clear (); |
535 |
return t; |
508 |
return t; |
|
|
509 |
} |
510 |
} |
536 |
} |
511 |
} |
537 |
} |
512 |
|
538 |
|
Lines 515-521
Link Here
|
515 |
/* One item representing the task pending in the pending queue */ |
541 |
/* One item representing the task pending in the pending queue */ |
516 |
private static class Item extends Exception { |
542 |
private static class Item extends Exception { |
517 |
private final RequestProcessor owner; |
543 |
private final RequestProcessor owner; |
518 |
private Task action; |
544 |
private Object action; |
519 |
private boolean enqueued; |
545 |
private boolean enqueued; |
520 |
|
546 |
|
521 |
Item (Task task, RequestProcessor rp) { |
547 |
Item (Task task, RequestProcessor rp) { |
Lines 525-545
Link Here
|
525 |
} |
551 |
} |
526 |
|
552 |
|
527 |
Task getTask() { |
553 |
Task getTask() { |
528 |
return action; |
554 |
Object a = action; |
|
|
555 |
return a instanceof Task ? (Task)a : null; |
529 |
} |
556 |
} |
530 |
|
557 |
|
531 |
/** Annulate this request iff still possible. |
558 |
/** Annulate this request iff still possible. |
532 |
* @returns true if it was possible to skip this item, false |
559 |
* @returns true if it was possible to skip this item, false |
533 |
* if the item was/is already processed */ |
560 |
* if the item was/is already processed */ |
534 |
boolean clear() { |
561 |
boolean clear(Processor processor) { |
535 |
synchronized (owner.processorLock) { |
562 |
synchronized (owner.processorLock) { |
536 |
action = null; |
563 |
action = processor; |
537 |
return enqueued ? owner.queue.remove(this) : true; |
564 |
return enqueued ? owner.queue.remove(this) : true; |
538 |
} |
565 |
} |
539 |
} |
566 |
} |
|
|
567 |
|
568 |
Processor getProcessor () { |
569 |
Object a = action; |
570 |
return a instanceof Processor ? (Processor)a : null; |
571 |
} |
540 |
|
572 |
|
541 |
int getPriority() { |
573 |
int getPriority() { |
542 |
return action.getPriority(); |
574 |
return getTask ().getPriority(); |
543 |
} |
575 |
} |
544 |
|
576 |
|
545 |
public Throwable fillInStackTrace() { |
577 |
public Throwable fillInStackTrace() { |
Lines 603-608
Link Here
|
603 |
|
635 |
|
604 |
private RequestProcessor source; |
636 |
private RequestProcessor source; |
605 |
|
637 |
|
|
|
638 |
/** task we are working on */ |
639 |
private RequestProcessor.Task todo; |
640 |
|
606 |
/* One minute of inactivity and the Thread will die if not assigned */ |
641 |
/* One minute of inactivity and the Thread will die if not assigned */ |
607 |
private static final int INACTIVE_TIMEOUT = 60000; |
642 |
private static final int INACTIVE_TIMEOUT = 60000; |
608 |
|
643 |
|
Lines 663-675
Link Here
|
663 |
} |
698 |
} |
664 |
} |
699 |
} |
665 |
|
700 |
|
666 |
Task todo; |
|
|
667 |
|
668 |
ErrorManager em = logger(); |
701 |
ErrorManager em = logger(); |
669 |
boolean loggable = em.isLoggable(ErrorManager.INFORMATIONAL); |
702 |
boolean loggable = em.isLoggable(ErrorManager.INFORMATIONAL); |
670 |
if (loggable) em.log (ErrorManager.INFORMATIONAL, "Begining work " + getName ()); // NOI18N |
703 |
if (loggable) em.log (ErrorManager.INFORMATIONAL, "Begining work " + getName ()); // NOI18N |
671 |
// while we have something to do |
704 |
// while we have something to do |
672 |
while((todo = current.askForWork(this)) != null) { |
705 |
for (;;) { |
|
|
706 |
// need the same sync as interruptTask |
707 |
synchronized (current.processorLock) { |
708 |
todo = current.askForWork(this); |
709 |
if (todo == null) break; |
710 |
} |
711 |
|
673 |
if(todo != null) { |
712 |
if(todo != null) { |
674 |
setPrio(todo.getPriority()); |
713 |
setPrio(todo.getPriority()); |
675 |
try { |
714 |
try { |
Lines 685-699
Link Here
|
685 |
doNotify(todo, e); |
724 |
doNotify(todo, e); |
686 |
} |
725 |
} |
687 |
// do not catch e.g. OutOfMemoryError, etc. |
726 |
// do not catch e.g. OutOfMemoryError, etc. |
688 |
|
727 |
|
689 |
// to improve GC |
728 |
// need the same sync as interruptTask |
690 |
todo = null; |
729 |
synchronized (current.processorLock) { |
|
|
730 |
// to improve GC |
731 |
todo = null; |
732 |
// and to clear any possible interrupted state |
733 |
// set by calling Task.cancel () |
734 |
Thread.interrupted(); |
735 |
} |
691 |
} |
736 |
} |
692 |
} |
737 |
} |
693 |
|
738 |
|
694 |
if (loggable) logger ().log (ErrorManager.INFORMATIONAL, "Work finished " + getName ()); // NOI18N |
739 |
if (loggable) logger ().log (ErrorManager.INFORMATIONAL, "Work finished " + getName ()); // NOI18N |
695 |
} |
740 |
} |
696 |
} |
741 |
} |
|
|
742 |
|
743 |
/** Called under the processorLock */ |
744 |
public void interruptTask (Task t) { |
745 |
if (t != todo) { |
746 |
// not running this task so |
747 |
return; |
748 |
} |
749 |
|
750 |
// otherwise interrupt this thread |
751 |
interrupt (); |
752 |
} |
697 |
|
753 |
|
698 |
/** @see "#20467" */ |
754 |
/** @see "#20467" */ |
699 |
private static void doNotify(RequestProcessor.Task todo, Throwable ex) { |
755 |
private static void doNotify(RequestProcessor.Task todo, Throwable ex) { |