File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\util\SequentialExecutionQueue.java.html

1 package hudson.util;
2
3 import java.util.HashMap;
4 import java.util.Map;
5 import java.util.Set;
6 import java.util.HashSet;
7 import java.util.concurrent.Executor;
8 import java.util.concurrent.ExecutorService;
9
10 /**
11 * {@link Executor} that collapses two equal {@link Runnable}s into one,
12 * and makes sure no two equal {@link Runnable}s get executed simultaneously.
13 *
14 * <p>
15 * That is, if a {@link Runnable} is executing and another one gets submitted,
16 * the 2nd one waits for the completion of the 1st one.
17 *
18 * {@link Object#equals(Object)} is used on {@link Runnable} to identify
19 * two equal {@link Runnable}s.
20 *
21 * @author Kohsuke Kawaguchi
22 */
23 public class SequentialExecutionQueue implements Executor {
24 /**
25 * Access is sycnhronized by {@code Queue.this}
26 */
27 private final Map<Runnable,QueueEntry> entries = new HashMap<Runnable,QueueEntry>();
28 private ExecutorService executors;
29
30 /**
31 * {@link Runnable}s that are currently executing. Useful for trouble-shooting.
32 */
33 private final Set<QueueEntry> inProgress = new HashSet<QueueEntry>();
34
35 public SequentialExecutionQueue(ExecutorService executors) {
36 this.executors = executors;
37 }
38
39 /**
40 * Gets the base underlying executors.,
41 */
42 public synchronized ExecutorService getExecutors() {
43 return executors;
44 }
45
46 /**
47 * Starts using a new {@link ExecutorService} to carry out executions.
48 *
49 * <p>
50 * The older {@link ExecutorService} will be shut down (but it's still expected to
51 * complete whatever they are doing and scheduled.)
52 */
53 public synchronized void setExecutors(ExecutorService svc) {
54 ExecutorService old = this.executors;
55 this.executors = svc;
56 // gradually executions will be taken over by a new pool
57 old.shutdown();
58 }
59
60
61 public synchronized void execute(Runnable item) {
62 QueueEntry e = entries.get(item);
63 if(e==null) {
64 e = new QueueEntry(item);
65 entries.put(item,e);
66 e.submit();
67 } else {
68 e.queued = true;
69 }
70 }
71
72 /**
73 * Returns true if too much time is spent since some {@link Runnable} is submitted into the queue
74 * until they get executed.
75 */
76 public synchronized boolean isStarving(long threshold) {
77 long now = System.currentTimeMillis();
78 for (QueueEntry e : entries.values())
79 if (now-e.submissionTime > threshold)
80 return true;
81 return false;
82 }
83
84 /**
85 * Gets {@link Runnable}s that are currently executed by a live thread.
86 */
87 public synchronized Set<Runnable> getInProgress() {
88 Set<Runnable> items = new HashSet<Runnable>();
89 for (QueueEntry entry : inProgress) {
90 items.add(entry.item);
91 }
92 return items;
93 }
94
95 private final class QueueEntry implements Runnable {
96 private final Runnable item;
97 private boolean queued;
98 private long submissionTime;
99
100 private QueueEntry(Runnable item) {
101 this.item = item;
102 this.queued = true;
103 }
104
105 // Caller must have a lock
106 private void submit() {
107 submissionTime = System.currentTimeMillis();
108 executors.submit(this);
109 }
110
111 public void run() {
112 try {
113 synchronized (SequentialExecutionQueue.this) {
114 assert queued;
115 queued = false;
116 inProgress.add(this);
117 }
118 item.run();
119 } finally {
120 synchronized (SequentialExecutionQueue.this) {
121 if(queued)
122 // another polling for this job is requested while we were doing the polling. do it again.
123 submit();
124 else
125 entries.remove(item);
126 inProgress.remove(this);
127 }
128 }
129 }
130 }
131 }
132