JSR-166: Concurrency Utilities Present and Future The java.util.concurrent package aims to do for concurrency what JSR-166 is based on over 3 years experience with java.util.Collections did for data structures. It makes http://gee.cs.oswego.edu http://gee.cs.oswego.edu EDU.oswego.cs.dl.util.concurrent Some problems go away Many refactorings and functionality improvements Some problems trivial to solve by everyone Additional native/JVM support Some problems easier to solve by concurrent programmers Timing, atomics, built-in monitor extensions Some problems possible to solve by experts A preliminary release of JSR-166 APIs, implementations, and JVM enhancements will be available soon Whenever you are about to use... Object.wait, notify, notifyAll, synchronized, new Thread(); Check first if there is a class that ... � automates what you are trying to do, or � would be a simpler starting point for your own solution JSR-166 Components Main Interfaces http://gee.cs.oswego.edu http://gee.cs.oswego.edu Lock Condition Collection Executors, Thread pools, and Futures void await() void lock() void signal() Queues and blocking queues void unlock() Queue ... boolean trylock() Timing boolean add(Object x) newCondition() Object poll() ... Locks and Conditions Synchronizers: Semaphores, Barriers, etc ReentrantLock ... BlockingQueue LinkedQ Atomic variables void put(Object x) Miscellany Object take(); ... Executor void execute(Runnable r) ... LinkedBQ ArrayBQ ThreadExecutor
Executors Thread Pools in Service Designs http://gee.cs.oswego.edu http://gee.cs.oswego.edu Pool client Standardize asynchronous invocation Worker � use anExecutor.execute(aRunnable) client Server task task � not new Thread(aRunnable).start() Worker Two styles supported: client � Actions: Runnables Worker � Functions (indirectly): Callables � Also cancellation and shutdown support Most access via Executors utility class � Configures very flexible ThreadExecutor � Also ScheduledExecutor for time-delayed tasks Thread Pool Example Thread Pools ThreadExecutors can vary in: http://gee.cs.oswego.edu http://gee.cs.oswego.edu The kind of task queue class WebService { Maximum and minimum number of threads public static void main(String[] args) { Executor pool = Shutdown policy Executors.newFixedThreadPool(7); Immediate, wait for current tasks ServerSocket socket = new ServerSocket(999); Keep-alive interval until idle threads die for (;;) { To be later replaced by new ones if necessary final Socket connection = socket.accept(); Before/after methods around tasks pool.execute(new Runnable() { public void run() { Factory methods package some common settings new Handler().process(connection); newSingleThreadExecutor() }}); } newFixedThreadPool(int nthreads) } newCachedThreadPool() } Reuses threads when available, else constructs class Handler { void process(Socket s); }
Futures and Callables Futures Example http://gee.cs.oswego.edu class ImageRenderer { Image render(byte[] raw); } http://gee.cs.oswego.edu class App { // ... Callable is functional analog of Runnable Executor executor = ...; // any executor ImageRenderer renderer = new ImageRenderer(); interface Callable<V> { public void display(final byte[] rawimage) { V call() throws Exception; try { } Future<Image> image = Executors.invoke(executor, new Callable<Image>(){ � Normally implement with an inner class that supplies public Image call() { arguments to the function return renderer.render(rawImage); }}); Future holds result of asynchronous call, normally to a drawBorders(); // do other things ... drawCaption(); // ... while executing Callable drawImage(image.get()); // use future interface Future<V> { } V get() throws InterruptedException, catch (Exception ex) { cleanup(); ExecutionException; return; // plus timeout versions and misc } } } } Queues Blocking Queues http://gee.cs.oswego.edu http://gee.cs.oswego.edu Queue interface added to java.util interface BlockingQueue<E> extends Queue<E> { void put(E x) throws IE; interface Queue<E> extends Collection<E>{ boolean offer(E x, long time,TimeUnit unit) boolean add(E x); throws InterruptedException; E poll(); E remove() throws NoSuchElem...; E take() throws InterruptedException; E peek(); E poll(long timeout, TimeUnit unit) E element() throws NoSuchEle..; throwsInterruptedException; } } � Retrofit (non-thread-safe) java.util.LinkedList to � Common in producer-consumer designs implement Some first-rate implementations � Add (non-thread-safe) java.util.PriorityQueue LinkedBlockingQueue , PriorityBlockingQueue , � Fast thread-safe non-blocking ArrayBlockingQueue , and SynchronousQueue java.util.concurrent.LinkedQueue
Blocking Queue Example TimeUnits http://gee.cs.oswego.edu http://gee.cs.oswego.edu class LoggedService { // ... Standardize time usage across APIs, without forcing use of final BlockingQueue<String> msgQ = inappropriate units new LinkedBlockingQueue<String>(); public void serve() throws InterruptedException { � SECONDS , MILLISECONDS , MICROSECONDS , NANOSECONDS // ... perform service ... producer x = queue.poll(3, TimeUnit.SECONDS) String status = ... ; msgQ.put(status); � TimeUnit class also supplies conversions and other time- } based utilities public LoggedService() { // start background thread Runnable logr = new Runnable() { Provides high resolution timing support public void run() { consumer try { � static long nanoTime() for(;;) � Value is unrelated to java.util.Date, System.out.println(msqQ.take()); System.currentTimeMillis etc } catch(InterruptedException ie) {} }}; Executors.newSingleThreadExecutor().execute(logr); } Blocking } queue Locks Lock API http://gee.cs.oswego.edu http://gee.cs.oswego.edu Flexibility at expense of verbosity interface Lock { lock.lock(); void lock(); try { void lockInterruptibly() throws IE; action(); boolean trylock(); } boolean trylock(long timeout, TimeUnit unit)throws IE; finally { lock.unlock(); void unlock(); } Condition newCondition(); } Concrete ReentrantLock implementation Overcomes limitations of synchronized � Fast, scalable with synchronized block semantics, and � Doesn’t force block structured locking/unlocking additional query methods � Allow interruptible lock acquisition and “try lock” � Also FairReentrantLock subclass with slower but more � Can define customized implementations predictable first-in-first-out arbitration
Lock Example Read-Write Locks class ParticleUsingLock { http://gee.cs.oswego.edu private int x, y; http://gee.cs.oswego.edu private final Random rng = new Random(); private final Lock lock = new ReentrantLock(); interface ReadWriteLock { Lock readLock(); public void move() throws InterruptedException { Lock writeLock(); lock.lockInterruptibly(); // allow cancellation } try { x += rng.nextInt(3) - 1; A pair of locks for enforcing multiple-reader, single-writer y += rng.nextInt(3) – 1; access } finally { lock.unlock(); } � Each used in the same way as ordinary locks } Concrete ReentrantReadWriteLock public void draw(Graphics g) { int lx, ly; � Almost always the best choice for apps lock.lock(); // no interrupts – AWT Event Thread try { � Each lock acts like a reentrant lock lx = x; ly = y; � Write lock can “downgrade” to read lock (not vice-versa) } finally { lock.unlock(); } g.drawRect(lx, ly, 10, 10); } } } Conditions Bounded Buffers using Conditions class BoundedBuffer { http://gee.cs.oswego.edu Lock lock = new ReentrantLock(); http://gee.cs.oswego.edu Condition notFull = lock.newCondition(); Condition notEmpty = lock.newCondition(); interface Condition { Object[] items = new Object[100]; void await() throws IE; int putptr, takeptr, count; void awaitUninterruptibly(); public void put(Object x)throws IE { lock.lock(); try { long awaitNanos(long nanos) throws IE; while (count == items.length)notFull.await(); boolean awaitUntil(Date deadline) throws IE; items[putptr] = x; void signal(); if (++putptr == items.length) putptr = 0; ++count; void signalAll(); notEmpty.signal(); } } finally { lock.unlock(); } } Allows more than one wait condition per object public Object take() throws IE { lock.lock(); try { � Even for built-in locks, via Locks utility class while (count == 0) notEmpty.await(); Object x = items[takeptr]; Allows much simpler implementation of some classic if (++takeptr == items.length) takeptr = 0; concurrent designs --count; notFull.signal(); return x; } finally { lock.unlock(); } } }
Recommend
More recommend