Author: toad
Date: 2007-08-11 13:49:20 +0000 (Sat, 11 Aug 2007)
New Revision: 14600

Added:
   trunk/freenet/src/freenet/support/Executor.java
   trunk/freenet/src/freenet/support/PooledExecutor.java
Log:
Add Executor interface (clone of java.util.concurrent) and homegrown 
PooledExecutor impl (we create a thread when we need one, they die after 5 
minutes of inactivity)

Added: trunk/freenet/src/freenet/support/Executor.java
===================================================================
--- trunk/freenet/src/freenet/support/Executor.java                             
(rev 0)
+++ trunk/freenet/src/freenet/support/Executor.java     2007-08-11 13:49:20 UTC 
(rev 14600)
@@ -0,0 +1,14 @@
+/**
+ * @author toad
+ * To the extent that this is copyrightable, it's part of Freenet and licensed 
+ * under GPL2 or later. However, it's a trivial interface taken from Sun JDK 
1.5,
+ * and we will use that when we migrate to 1.5.
+ */
+package freenet.support;
+
+public interface Executor {
+       
+       /** Execute a job. */
+       public void execute(Runnable job);
+
+}

Added: trunk/freenet/src/freenet/support/PooledExecutor.java
===================================================================
--- trunk/freenet/src/freenet/support/PooledExecutor.java                       
        (rev 0)
+++ trunk/freenet/src/freenet/support/PooledExecutor.java       2007-08-11 
13:49:20 UTC (rev 14600)
@@ -0,0 +1,101 @@
+package freenet.support;
+
+import java.util.ArrayList;
+
+public class PooledExecutor implements Executor {
+
+       private final ArrayList runningThreads /* <MyThread> */ = new 
ArrayList();
+       private final ArrayList waitingThreads /* <MyThread> */ = new 
ArrayList();
+       long threadCounter = 0;
+       
+       /** Maximum time a thread will wait for a job */
+       static final int TIMEOUT = 5*60*1000;
+       
+       public void execute(Runnable job) {
+               while(true) {
+                       MyThread t;
+                       boolean mustStart = false;
+                       synchronized(this) {
+                               if(!waitingThreads.isEmpty()) {
+                                       t = (MyThread) 
waitingThreads.remove(waitingThreads.size()-1);
+                               } else {
+                                       t = new MyThread("Pooled thread 
"+(threadCounter++));
+                                       t.setDaemon(true);
+                                       mustStart = true;
+                               }
+                       }
+                       synchronized(t) {
+                               if(!t.alive) continue;
+                               if(t.nextJob != null) continue;
+                               t.nextJob = job;
+                               if(!mustStart)
+                                       t.notify();
+                       }
+                       if(mustStart) {
+                               t.start();
+                               synchronized(this) {
+                                       runningThreads.add(t);
+                               }
+                       }
+                       return;
+               }
+       }
+
+       class MyThread extends Thread {
+               
+               boolean alive = true;
+               Runnable nextJob;
+               
+               public MyThread(String string) {
+                       super(string);
+               }
+
+               public void run() {
+                       while(true) {
+                               Runnable job;
+                               
+                               synchronized(this) {
+                                       job = nextJob;
+                                       nextJob = null;
+                               }
+                               
+                               if(job == null) {
+                                       synchronized(PooledExecutor.this) {
+                                               waitingThreads.add(this);
+                                       }
+                                       synchronized(this) {
+                                               if(nextJob == null) {
+                                                       try {
+                                                               wait(TIMEOUT);
+                                                       } catch 
(InterruptedException e) {
+                                                               // Ignore
+                                                       }
+                                               }
+                                               job = nextJob;
+                                               nextJob = null;
+                                               if(job == null) {
+                                                       alive = false;
+                                                       // execute() won't give 
us another one if alive = false
+                                               }
+                                       }
+                                       synchronized(PooledExecutor.this) {
+                                               waitingThreads.remove(this);
+                                               if(!alive) {
+                                                       
runningThreads.remove(this);
+                                                       return;
+                                               }
+                                       }
+                               }
+                               
+                               // Run the job
+                               try {
+                                       job.run();
+                               } catch (Throwable t) {
+                                       Logger.error(this, "Caught "+t+" 
running job "+job, t);
+                               }
+                       }
+               }
+               
+       }
+       
+}


Reply via email to