blob: 05a99e299c987d984894149ae923ca940114bf0a [file] [log] [blame]
Marcel Offermans89a8a6b2007-06-08 21:27:59 +00001package org.apache.felix.dependencymanager;
2
3import java.util.LinkedList;
4import java.util.NoSuchElementException;
5
6/**
7 * Allows you to enqueue tasks from multiple threads and then execute
8 * them on one thread sequentially. It assumes more than one thread will
9 * try to execute the tasks and it will make an effort to pick the first
10 * task that comes along whilst making sure subsequent tasks return
11 * without waiting.
12 *
13 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
14 */
15public final class SerialExecutor {
16 private final LinkedList m_workQueue = new LinkedList();
17 private Runnable m_active;
18
19 /**
20 * Enqueue a new task for later execution. This method is
21 * thread-safe, so multiple threads can contribute tasks.
22 *
23 * @param runnable the runnable containing the actual task
24 */
25 public synchronized void enqueue(final Runnable runnable) {
26 m_workQueue.addLast(new Runnable() {
27 public void run() {
28 try {
29 runnable.run();
30 }
31 finally {
32 scheduleNext();
33 }
34 }
35 });
36 }
37
38 /**
39 * Execute any pending tasks. This method is thread safe,
40 * so multiple threads can try to execute the pending
41 * tasks, but only the first will be used to actually do
42 * so. Other threads will return immediately.
43 */
44 public void execute() {
45 Runnable active;
46 synchronized (this) {
47 active = m_active;
48 }
49 if (active == null) {
50 scheduleNext();
51 }
52 }
53
54 private void scheduleNext() {
55 Runnable active;
56 synchronized (this) {
57 try {
58 m_active = (Runnable) m_workQueue.removeFirst();
59 }
60 catch (NoSuchElementException e) {
61 m_active = null;
62 }
63 active = m_active;
64 }
65 if (active != null) {
66 active.run();
67 }
68 }
69
70 /*
71 class SerialExecutor implements Executor {
72 final Queue<Runnable> tasks = new LinkedBlockingQueue<Runnable>();
73 final Executor executor;
74 Runnable active;
75
76 SerialExecutor(Executor executor) {
77 this.executor = executor;
78 }
79
80 public synchronized void execute(final Runnable r) {
81 tasks.offer(new Runnable() {
82 public void run() {
83 try {
84 r.run();
85 } finally {
86 scheduleNext();
87 }
88 }
89 });
90 if (active == null) {
91 scheduleNext();
92 }
93 }
94
95 protected synchronized void scheduleNext() {
96 if ((active = tasks.poll()) != null) {
97 executor.execute(active);
98 }
99 }
100 }
101 */
102
103
104 // just some test code ;)
105 public static void main(String[] args) {
106 final SerialExecutor se = new SerialExecutor();
107 (new Thread("T1") { public void run() {
108 for (int i = 0; i < 100; i++) {
109 final int nr = i;
110 se.enqueue(new Runnable() { public void run() {
111 System.out.println("A" + nr + ":" + Thread.currentThread().getName());
112 if (nr % 10 == 5) {
113 try { Thread.sleep(10); } catch (InterruptedException ie) {}
114 }
115 }});
116 try { Thread.sleep(1); } catch (InterruptedException ie) {}
117 se.execute();
118 }
119 System.out.println("A is done");
120 }}).start();
121 try { Thread.sleep(5); } catch (InterruptedException ie) {}
122 (new Thread("T2") { public void run() {
123 for (int i = 0; i < 100; i++) {
124 final int nr = i;
125 se.enqueue(new Runnable() { public void run() {
126 System.out.println("B" + nr + ":" + Thread.currentThread().getName());
127 if (nr % 19 == 6) {
128 try { Thread.sleep(20); } catch (InterruptedException ie) {}
129 }
130 }});
131 try { Thread.sleep(1); } catch (InterruptedException ie) {}
132 se.execute();
133 }
134 System.out.println("B is done");
135 }}).start();
136 try { Thread.sleep(5); } catch (InterruptedException ie) {}
137 (new Thread("T3") { public void run() {
138 for (int i = 0; i < 100; i++) {
139 final int nr = i;
140 se.enqueue(new Runnable() { public void run() {
141 System.out.println("C" + nr + ":" + Thread.currentThread().getName());
142 }});
143 se.execute();
144 }
145 System.out.println("C is done");
146 }}).start();
147 }
148}