Lines 24-30
import java.util.*;
Link Here
|
24 |
* |
24 |
* |
25 |
* <P><A name="use_cases">There are several use cases for RequestProcessor:</A> |
25 |
* <P><A name="use_cases">There are several use cases for RequestProcessor:</A> |
26 |
* |
26 |
* |
27 |
* <UL><LI>Having something done asynchronously in some other thread, |
27 |
* <UL><LI>Having something done asynchronously in some other thread, |
28 |
* not insisting on any kind of serialization of the requests: |
28 |
* not insisting on any kind of serialization of the requests: |
29 |
* Use <CODE>RequestProcessor.{@link RequestProcessor#getDefault |
29 |
* Use <CODE>RequestProcessor.{@link RequestProcessor#getDefault |
30 |
* }.{@link #post(java.lang.Runnable) post(runnable)}</CODE> |
30 |
* }.{@link #post(java.lang.Runnable) post(runnable)}</CODE> |
Lines 64-69
import java.util.*;
Link Here
|
64 |
* <CODE>RequestProcessor</CODE> instance with limited throughput (probably |
64 |
* <CODE>RequestProcessor</CODE> instance with limited throughput (probably |
65 |
* set to 1), the IDE would try to run all your requests in parallel otherwise. |
65 |
* set to 1), the IDE would try to run all your requests in parallel otherwise. |
66 |
* |
66 |
* |
|
|
67 |
* <P> |
68 |
* Since version JST-PENDING there is a support for interruption of long running tasks. |
69 |
* There always was a way how to cancel not yet running task using {@link RequestProcessor.Task#cancel } |
70 |
* but if the task was already running, one was out of luck. Since version 4.6 |
71 |
* the thread running the task is interrupted and the Runnable can check for that |
72 |
* and terminate its execution sooner. In the runnable one shall check for |
73 |
* thread interruption (done from {@link RequestProcessor.Task#cancel }) and |
74 |
* if true, return immediatelly as in this example: |
75 |
* <PRE> |
76 |
* public void run () { |
77 |
* while (veryLongTimeLook) { |
78 |
* doAPieceOfIt (); |
79 |
* |
80 |
* if (Thread.interrupted ()) return; |
81 |
* } |
82 |
* } |
83 |
* </PRE> |
84 |
* |
67 |
* @author Petr Nejedly, Jaroslav Tulach |
85 |
* @author Petr Nejedly, Jaroslav Tulach |
68 |
*/ |
86 |
*/ |
69 |
public final class RequestProcessor { |
87 |
public final class RequestProcessor { |
Lines 364-384
public final class RequestProcessor {
Link Here
|
364 |
} |
382 |
} |
365 |
|
383 |
|
366 |
Task askForWork(Processor worker, String debug) { |
384 |
Task askForWork(Processor worker, String debug) { |
367 |
synchronized (processorLock) { |
385 |
if (stopped || queue.isEmpty()) { // no more work in this burst, return him |
368 |
if (stopped || queue.isEmpty()) { // no more work in this burst, return him |
386 |
processors.remove(worker); |
369 |
processors.remove(worker); |
387 |
Processor.put(worker, debug); |
370 |
Processor.put(worker, debug); |
388 |
running--; |
371 |
running--; |
389 |
|
372 |
|
390 |
return null; |
373 |
return null; |
391 |
} else { // we have some work for the worker, pass it |
374 |
} else { // we have some work for the worker, pass it |
392 |
|
375 |
|
393 |
Item i = (Item) queue.remove(0); |
376 |
Item i = (Item) queue.remove(0); |
394 |
Task t = i.getTask(); |
377 |
Task t = i.getTask(); |
395 |
i.clear(worker); |
378 |
i.clear(); |
|
|
379 |
|
396 |
|
380 |
return t; |
397 |
return t; |
381 |
} |
|
|
382 |
} |
398 |
} |
383 |
} |
399 |
} |
384 |
|
400 |
|
Lines 458-464
public final class RequestProcessor {
Link Here
|
458 |
notifyRunning(); |
474 |
notifyRunning(); |
459 |
|
475 |
|
460 |
if (item != null) { |
476 |
if (item != null) { |
461 |
item.clear(); |
477 |
item.clear(null); |
462 |
} |
478 |
} |
463 |
|
479 |
|
464 |
item = new Item(this, RequestProcessor.this); |
480 |
item = new Item(this, RequestProcessor.this); |
Lines 490-496
public final class RequestProcessor {
Link Here
|
490 |
*/ |
506 |
*/ |
491 |
public boolean cancel() { |
507 |
public boolean cancel() { |
492 |
synchronized (processorLock) { |
508 |
synchronized (processorLock) { |
493 |
boolean success = (item == null) ? false : item.clear(); |
509 |
boolean success; |
|
|
510 |
|
511 |
if (item == null) { |
512 |
success = false; |
513 |
} else { |
514 |
Processor p = item.getProcessor(); |
515 |
success = item.clear(null); |
516 |
|
517 |
if (p != null) { |
518 |
p.interruptTask(this); |
519 |
item = null; |
520 |
} |
521 |
} |
494 |
|
522 |
|
495 |
if (success) { |
523 |
if (success) { |
496 |
notifyFinished(); // mark it as finished |
524 |
notifyFinished(); // mark it as finished |
Lines 541-557
public final class RequestProcessor {
Link Here
|
541 |
*/ |
569 |
*/ |
542 |
public void waitFinished() { |
570 |
public void waitFinished() { |
543 |
if (isRequestProcessorThread()) { //System.err.println("Task.waitFinished on " + this + " from other task in RP: " + Thread.currentThread().getName()); |
571 |
if (isRequestProcessorThread()) { //System.err.println("Task.waitFinished on " + this + " from other task in RP: " + Thread.currentThread().getName()); |
544 |
|
|
|
545 |
boolean toRun; |
572 |
boolean toRun; |
546 |
|
573 |
|
547 |
synchronized (processorLock) { |
574 |
synchronized (processorLock) { |
548 |
// correct line: toRun = (item == null) ? !isFinished (): (item.clear() && !isFinished ()); |
575 |
// correct line: toRun = (item == null) ? !isFinished (): (item.clear() && !isFinished ()); |
549 |
// the same: toRun = !isFinished () && (item == null ? true : item.clear ()); |
576 |
// the same: toRun = !isFinished () && (item == null ? true : item.clear ()); |
550 |
toRun = !isFinished() && ((item == null) || item.clear()); |
577 |
toRun = !isFinished() && ((item == null) || item.clear(null)); |
551 |
} |
578 |
} |
552 |
|
579 |
|
553 |
if (toRun) { //System.err.println(" ## running it synchronously"); |
580 |
if (toRun) { //System.err.println(" ## running it synchronously"); |
554 |
run(); |
581 |
Processor processor = (Processor)Thread.currentThread(); |
|
|
582 |
processor.doEvaluate (this, processorLock); |
555 |
} else { // it is already running in other thread of this RP |
583 |
} else { // it is already running in other thread of this RP |
556 |
|
584 |
|
557 |
if (lastThread != Thread.currentThread()) { |
585 |
if (lastThread != Thread.currentThread()) { |
Lines 586-592
public final class RequestProcessor {
Link Here
|
586 |
boolean toRun; |
614 |
boolean toRun; |
587 |
|
615 |
|
588 |
synchronized (processorLock) { |
616 |
synchronized (processorLock) { |
589 |
toRun = !isFinished() && ((item == null) || item.clear()); |
617 |
toRun = !isFinished() && ((item == null) || item.clear(null)); |
590 |
} |
618 |
} |
591 |
|
619 |
|
592 |
if (toRun) { |
620 |
if (toRun) { |
Lines 614-620
public final class RequestProcessor {
Link Here
|
614 |
/* One item representing the task pending in the pending queue */ |
642 |
/* One item representing the task pending in the pending queue */ |
615 |
private static class Item extends Exception { |
643 |
private static class Item extends Exception { |
616 |
private final RequestProcessor owner; |
644 |
private final RequestProcessor owner; |
617 |
private Task action; |
645 |
private Object action; |
618 |
private boolean enqueued; |
646 |
private boolean enqueued; |
619 |
|
647 |
|
620 |
Item(Task task, RequestProcessor rp) { |
648 |
Item(Task task, RequestProcessor rp) { |
Lines 624-645
public final class RequestProcessor {
Link Here
|
624 |
} |
652 |
} |
625 |
|
653 |
|
626 |
Task getTask() { |
654 |
Task getTask() { |
627 |
return action; |
655 |
Object a = action; |
|
|
656 |
|
657 |
return (a instanceof Task) ? (Task) a : null; |
628 |
} |
658 |
} |
629 |
|
659 |
|
630 |
/** Annulate this request iff still possible. |
660 |
/** Annulate this request iff still possible. |
631 |
* @returns true if it was possible to skip this item, false |
661 |
* @returns true if it was possible to skip this item, false |
632 |
* if the item was/is already processed */ |
662 |
* if the item was/is already processed */ |
633 |
boolean clear() { |
663 |
boolean clear(Processor processor) { |
634 |
synchronized (owner.processorLock) { |
664 |
synchronized (owner.processorLock) { |
635 |
action = null; |
665 |
action = processor; |
636 |
|
666 |
|
637 |
return enqueued ? owner.queue.remove(this) : true; |
667 |
return enqueued ? owner.queue.remove(this) : true; |
638 |
} |
668 |
} |
639 |
} |
669 |
} |
640 |
|
670 |
|
|
|
671 |
Processor getProcessor() { |
672 |
Object a = action; |
673 |
|
674 |
return (a instanceof Processor) ? (Processor) a : null; |
675 |
} |
676 |
|
641 |
int getPriority() { |
677 |
int getPriority() { |
642 |
return action.getPriority(); |
678 |
return getTask().getPriority(); |
643 |
} |
679 |
} |
644 |
|
680 |
|
645 |
public Throwable fillInStackTrace() { |
681 |
public Throwable fillInStackTrace() { |
Lines 669-674
public final class RequestProcessor {
Link Here
|
669 |
|
705 |
|
670 |
//private Item task; |
706 |
//private Item task; |
671 |
private RequestProcessor source; |
707 |
private RequestProcessor source; |
|
|
708 |
|
709 |
/** task we are working on */ |
710 |
private RequestProcessor.Task todo; |
672 |
private boolean idle = true; |
711 |
private boolean idle = true; |
673 |
|
712 |
|
674 |
/** Waiting lock */ |
713 |
/** Waiting lock */ |
Lines 771-777
public final class RequestProcessor {
Link Here
|
771 |
} |
810 |
} |
772 |
} |
811 |
} |
773 |
|
812 |
|
774 |
Task todo; |
|
|
775 |
String debug = null; |
813 |
String debug = null; |
776 |
|
814 |
|
777 |
ErrorManager em = logger(); |
815 |
ErrorManager em = logger(); |
Lines 782-789
public final class RequestProcessor {
Link Here
|
782 |
} |
820 |
} |
783 |
|
821 |
|
784 |
// while we have something to do |
822 |
// while we have something to do |
785 |
while ((todo = current.askForWork(this, debug)) != null) { |
823 |
for (;;) { |
786 |
// if(todo != null) { |
824 |
// need the same sync as interruptTask |
|
|
825 |
synchronized (current.processorLock) { |
826 |
todo = current.askForWork(this, debug); |
827 |
if (todo == null) break; |
828 |
} |
787 |
setPrio(todo.getPriority()); |
829 |
setPrio(todo.getPriority()); |
788 |
|
830 |
|
789 |
try { |
831 |
try { |
Lines 813-828
public final class RequestProcessor {
Link Here
|
813 |
doNotify(todo, t); |
855 |
doNotify(todo, t); |
814 |
} |
856 |
} |
815 |
|
857 |
|
816 |
// to improve GC |
858 |
// need the same sync as interruptTask |
817 |
todo = null; |
859 |
synchronized (current.processorLock) { |
818 |
|
860 |
// to improve GC |
819 |
// } |
861 |
todo = null; |
|
|
862 |
// and to clear any possible interrupted state |
863 |
// set by calling Task.cancel () |
864 |
Thread.interrupted(); |
865 |
} |
820 |
} |
866 |
} |
821 |
|
867 |
|
822 |
if (loggable) { |
868 |
if (loggable) { |
823 |
logger().log(ErrorManager.INFORMATIONAL, "Work finished " + getName()); // NOI18N |
869 |
logger().log(ErrorManager.INFORMATIONAL, "Work finished " + getName()); // NOI18N |
824 |
} |
870 |
} |
825 |
} |
871 |
} |
|
|
872 |
} |
873 |
|
874 |
/** Evaluates given task directly. |
875 |
*/ |
876 |
final void doEvaluate (Task t, Object processorLock) { |
877 |
Task previous = todo; |
878 |
boolean interrupted = Thread.interrupted(); |
879 |
try { |
880 |
todo = t; |
881 |
t.run (); |
882 |
} finally { |
883 |
synchronized (processorLock) { |
884 |
todo = previous; |
885 |
if (interrupted || todo.item == null) { |
886 |
Thread.currentThread().interrupt(); |
887 |
} |
888 |
} |
889 |
} |
890 |
} |
891 |
|
892 |
/** Called under the processorLock */ |
893 |
public void interruptTask(Task t) { |
894 |
if (t != todo) { |
895 |
// not running this task so |
896 |
return; |
897 |
} |
898 |
|
899 |
// otherwise interrupt this thread |
900 |
interrupt(); |
826 |
} |
901 |
} |
827 |
|
902 |
|
828 |
/** @see "#20467" */ |
903 |
/** @see "#20467" */ |