blob: 05a99e299c987d984894149ae923ca940114bf0a [file] [log] [blame]
package org.apache.felix.dependencymanager;
import java.util.LinkedList;
import java.util.NoSuchElementException;
/**
* Allows you to enqueue tasks from multiple threads and then execute
* them on one thread sequentially. It assumes more than one thread will
* try to execute the tasks and it will make an effort to pick the first
* task that comes along whilst making sure subsequent tasks return
* without waiting.
*
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public final class SerialExecutor {
private final LinkedList m_workQueue = new LinkedList();
private Runnable m_active;
/**
* Enqueue a new task for later execution. This method is
* thread-safe, so multiple threads can contribute tasks.
*
* @param runnable the runnable containing the actual task
*/
public synchronized void enqueue(final Runnable runnable) {
m_workQueue.addLast(new Runnable() {
public void run() {
try {
runnable.run();
}
finally {
scheduleNext();
}
}
});
}
/**
* Execute any pending tasks. This method is thread safe,
* so multiple threads can try to execute the pending
* tasks, but only the first will be used to actually do
* so. Other threads will return immediately.
*/
public void execute() {
Runnable active;
synchronized (this) {
active = m_active;
}
if (active == null) {
scheduleNext();
}
}
private void scheduleNext() {
Runnable active;
synchronized (this) {
try {
m_active = (Runnable) m_workQueue.removeFirst();
}
catch (NoSuchElementException e) {
m_active = null;
}
active = m_active;
}
if (active != null) {
active.run();
}
}
/*
class SerialExecutor implements Executor {
final Queue<Runnable> tasks = new LinkedBlockingQueue<Runnable>();
final Executor executor;
Runnable active;
SerialExecutor(Executor executor) {
this.executor = executor;
}
public synchronized void execute(final Runnable r) {
tasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (active == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((active = tasks.poll()) != null) {
executor.execute(active);
}
}
}
*/
// just some test code ;)
public static void main(String[] args) {
final SerialExecutor se = new SerialExecutor();
(new Thread("T1") { public void run() {
for (int i = 0; i < 100; i++) {
final int nr = i;
se.enqueue(new Runnable() { public void run() {
System.out.println("A" + nr + ":" + Thread.currentThread().getName());
if (nr % 10 == 5) {
try { Thread.sleep(10); } catch (InterruptedException ie) {}
}
}});
try { Thread.sleep(1); } catch (InterruptedException ie) {}
se.execute();
}
System.out.println("A is done");
}}).start();
try { Thread.sleep(5); } catch (InterruptedException ie) {}
(new Thread("T2") { public void run() {
for (int i = 0; i < 100; i++) {
final int nr = i;
se.enqueue(new Runnable() { public void run() {
System.out.println("B" + nr + ":" + Thread.currentThread().getName());
if (nr % 19 == 6) {
try { Thread.sleep(20); } catch (InterruptedException ie) {}
}
}});
try { Thread.sleep(1); } catch (InterruptedException ie) {}
se.execute();
}
System.out.println("B is done");
}}).start();
try { Thread.sleep(5); } catch (InterruptedException ie) {}
(new Thread("T3") { public void run() {
for (int i = 0; i < 100; i++) {
final int nr = i;
se.enqueue(new Runnable() { public void run() {
System.out.println("C" + nr + ":" + Thread.currentThread().getName());
}});
se.execute();
}
System.out.println("C is done");
}}).start();
}
}