// The idea is to leave max as the actual number of cores the system // has (numberOfCores()), and in case of being fully booked, raise an // alert (customerMustWaitAlert) which can be handled by a strategy // object (different reactions are possible). // If nothing is done in such an event, clients are processed serially // (no guarantees of order), split up among the available threads. sclass ThreadPool is AutoCloseable { int max = numberOfCores(); new Set used; new Set free; bool retired; *() {} *(int *max) {} synchronized int maxSize() { ret max; } synchronized int total() { ret l(used)+l(free); } event customerMustWaitAlert; void fireCustomerMustWaitAlert { vmBus_send customerMustWaitAlert(this, currentThread()); customerMustWaitAlert(); } synchronized Thread acquireThread(Runnable action) ctex { checkNotRetired(); if (empty(free)) { if (total() < max) free.add(newThread()); else do { fireCustomerMustWaitAlert(); wait(); checkNotRetired(); } while (empty(free)); } PooledThread t = first(free); t.addWork(action); // will move it from free to used ret t; } class PooledThread extends Thread { *(S name) { super(name); } AppendableChain q; synchronized Runnable _grabWork() { Runnable r = first(q); q = popFirst(q); if (r == null) threadIdling(this); ret r; } run { while ping (!retired()) { Runnable r = _grabWork(); if (r != null) pcall { r.run(); } else { synchronized { wait(); } } } } // append to q (do later) void addWork(Runnable r) { if (r == null) ret; synchronized { if (isEmpty(q)) markUsed(this); q = chainPlus(q, r); notify(); } } } PooledThread newThread() { PooledThread t = new("Thread Pool Inhabitant " + n2(total()+1)); t.setDaemon(true); t.start(); ret t; } synchronized void threadIdling(PooledThread t) { used.remove(t); free.add(t); notifyAll(); } synchronized void markUsed(PooledThread t) { free.remove(t); used.add(t); } synchronized toString { ret retired() ? "Retired ThreadPool" : "ThreadPool " + roundBracket(commaCombine( n2(used) + " used out of " + n2(total()), max <= total() ? null : "could grow to " + n2(max)); } synchronized bool retired() { ret retired; } synchronized void retire() { set retired; for (thread : free) syncNotifyAll(thread); // wake it up so it exits } void checkNotRetired { if (retired()) fail("retired"); } // We could do a soft-close here (stop the idle threads, let running threads finish, then end those too, stop accepting new orders) // or a hard close (interrupt all threads, stop accepting new orders) synchronized close { retire(); } }