Concurrency in JDK 5.0 - CIS Personal Web Pages

3 downloads 72 Views 134KB Size Report
Java Implicit Concurrency (3). • JDK 5.0. – java.util.concurrent. – JVM-level changes (exploitation of hardware level concurrency support – compare-and- swap.
CIT Concurrency

Concurrency in JDK 5.0 Thread-safe collections, Task Management, Synchronizers, Lowlevel Facilities

Java Implicit Concurrency (1) • AWT and Swing

CIT Concurrency

– Background event thread – Event Listener classes must be thread-safe

• TimeTask – scheduling and periodic execution of tasks – TimerTask events execute in the Timer thread – TimerTasks must be thread safe

• Servlets and JavaServer Pages – Servlet containers create multiple threads and may call a given servlet concurrently from multiple threads for multiple requests – Servlets classes must be thread safe

• RMI – Remote classes must be thread safe

Java Implicit Concurrency (2) • Thread safe class

CIT Concurrency

– Must behave correctly in a single-threaded environment • No sequence of operations (public interface) puts objects in an invalid state, • Or observe the object to be in an invalid state • Or violate any of the class’s invariants, pre- and postconditions

– Must continue to behave correctly when accessed from multiple threads • Regardless of the scheduling or interleaving of the execution of those threads by the runtime environment • Without any additional synchronisation on the part of the calling code

Java Implicit Concurrency (3)

CIT Concurrency

• JDK 5.0 – java.util.concurrent – JVM-level changes (exploitation of hardware level concurrency support – compare-and-swap instruction) – Low-level utility classes – locks and atomic variables – High-level utility classes – OS constructs (e.g. semaphores, mutexes, barriers), thread pools and thread-safe collection classes

Thread-safe collections (1)

CIT Concurrency

• Collections – Some are already thread safe: Hashtable and Vector – The rest can be made thread safe: syncrhonised wrapper factories Collections.synchronisedList/Map/Set – Need to hold a lock while iterating! • Fail-fast iterators • ConcurrentModificationException – conditional thread-safety

• java.util.concurrent – ConcurrentHashMap, CopyOnWriteArrayList, CoppyOnWriteArraySet, Queue, BlockingQueue • Weakly consistent iterators – A removed item not already returned will not be returned – An added item after the start of the iteration may or may not be returned – No element will be returned twice in a single iteration

Thread-safe collections (2)

CIT Concurrency

• CopyOnWriteArrayList/Set – A new copy is created whenever an element is added or removed – Avoids locking during iteration – Useful for list of listeners

• ConcurrentHashMap – Cannot be locked for exclusive use, but provides atomic methods for common compound operations, e.g. put-ifabsent – Returns weakly consistent iterators

• Queue interface – FIFO and priority classes • BlockingQueue – bounded or unbounded – Producer/Consumer

Bounded Buffer (1)

CIT Concurrency

• A bounded buffer consists of a fixed number of slots – Items are put into the buffer by a producer process and removed by a consumer process – It can be used to smooth out transfer rates between the producer and consumer

Bounded Buffer (2) We separate the interface to class BufferImpl implements Buffer { permit an … alternative public synchronized void put(Object o) throws InterruptedException {implementation later. while (count==size) wait(); buf[in] = o; ++count; in=(in+1)%size; notify(); } public synchronized Object get() throws InterruptedException { while (count==0) wait(); Object o =buf[out]; buf[out]=null; --count; out=(out+1)%size; notify(); return (o); }

CIT Concurrency

public interface Buffer {…}

}

Bounded Buffer (3) class Producer implements Runnable { Buffer buf; String alphabet= "abcdefghijklmnopqrstuvwxyz"; Producer(Buffer b) {buf = b;} CIT Concurrency

public void run() { try { int ai = 0; Similarly Consumer while(true) { which calls buf.get() ThreadPanel.rotate(12); buf.put(new Character(alphabet.charAt(ai))); ai=(ai+1) % alphabet.length(); ThreadPanel.rotate(348); } } catch (InterruptedException e){} } }

Bounded Buffer (4) • The same in java 5.0

CIT Concurrency

– The buffer LinkedBlockingQueue buf = new LinkedBlockingQueue(n);

– The consumer Character c = buf.take();

– The producer buf.put(new Character(alphabet.charAt(ai)));

Task Management (1)

CIT Concurrency

• Executor interface – Objects that run Runnables – Separate task submission from task execution policy – Various threading options: background thread, thread pool, in the calling thread (pass-through), new thread (thread-per-request), in another JVM – Instantiation through factory methods • Executors.newCachedThreadPool() • Executors.newFixedThreadPool(int n) • Executors.newSingleThreadExecutor()

• ExecutorService interface – Extension of executor with lifecycle management of execution service

CIT Concurrency

Task Management (2) class ReliableWebServer { Executor pool = Executors.newFixedThreadPool(7); public static void main(String[] args) { ServerSocket socket = new ServerSocket(80); while (true) { final Socket connection = socket.accept(); Runnable r = new Runnable() { public void run() { handleRequest(connection); } }; pool.execute(r); } } }

CIT Concurrency

Task Management (3) • Executor customisation through custom ThreadFactory • In case of execution inability – RejectedExecutionHandler – – – –

Throw exception Discard task Execute in caller’s thread Discard old task in queue

• Custom executors with overidden beforeExecute and afterExecute – Instrumentation, logging, timing, reinitialisation of thread-local variables, execution customisations

Task Management (4)

CIT Concurrency

• Callable: result bearing Runnable • Future interface – FutureTask – implements interface, can be submitted to an Executor • ExecutorService.submit() – returns a Future interface

– Future.get() – retrieves results or throws ExecutionException – it is blocking

• CompletionService interface – Decouple results processing from task execution, e.g. producer/consumer – ExecutorCompletionInterface

CIT Concurrency

Task Management (5) public class Cache { ConcurrentMap map = new ConcurrentHashMap(); Executor executor = Executors.newFixedThreadPool(8); public V get(final K key) { FutureTask f = map.get(key); if (f == null) { Callable c = new Callable() { public V call() { // return value associated with key } }; f = new FutureTask(c); FutureTask old = map.putIfAbsent(key, f); if (old == null) executor.execute(f); else f = old; } return f.get(); } }

Semaphores (1)

CIT Concurrency

• Semaphore s is an integer variable that can take only non-negative values – Semaphores are widely used for dealing with inter-process synchronization in operating systems

• The only operations permitted on s are up(s) and down(s) – Blocked processes are held in a FIFO queue.

down(s): if s >0 then decrement s else block execution of the calling process up(s):

if processes blocked on s then awaken one of them else increment s

Semaphores (2) public class Semaphore { private int value; CIT Concurrency

public Semaphore (int initial) { value = initial;} synchronized public void up() { ++value; notify(); } synchronized public void down() throws InterruptedException { while (value==0) wait(); --value; } }

Bounded Buffer (2) We separate the interface to class BufferImpl implements Buffer { permit an … alternative public synchronized void put(Object o) throws InterruptedException {implementation later. while (count==size) wait(); buf[in] = o; ++count; in=(in+1)%size; notify(); } public synchronized Object get() throws InterruptedException { while (count==0) wait(); Object o =buf[out]; buf[out]=null; --count; out=(out+1)%size; notify(); return (o); }

CIT Concurrency

public interface Buffer {…}

}

CIT Concurrency

Nested Monitors (1) • Suppose that, in place of using the count variable and condition synchronization directly, we instead use two semaphores full and empty to reflect the state of the buffer. class SemaBuffer implements Buffer { … Semaphore full; //counts number of items Semaphore empty; //counts number of spaces SemaBuffer(int size) { this.size = size; buf = new Object[size]; full = new Semaphore(0); empty= new Semaphore(size); } … }

CIT Concurrency

Nested Monitors (2) synchronized public void put(Object o) throws InterruptedException { empty.down(); buf[in] = o; Does this behave ++count; in=(in+1)%size; full.up(); as desired? } synchronized public Object get() throws InterruptedException{ full.down(); Object o =buf[out]; buf[out]=null; --count; out=(out+1)%size; empty.up(); return (o); }

• Empty is decremented during a put operation, which is blocked if empty is zero • Full is decremented by a get operation, which is blocked if full is zero.

Nested Monitors (3)

CIT Concurrency

• The only way to avoid nested monitor deadlock in Java is by careful design – In this example, the deadlock can be removed by ensuring that the monitor lock for the buffer is not acquired until after semaphores are decremented. public void put(Object o) throws InterruptedException { empty.down(); synchronized(this){ buf[in] = o; ++count; in=(in+1)%size; } full.up(); }

Syncrhonizer Classes • Coordination and control of execution flow of threads • Semaphore

CIT Concurrency

– Thread acquire any number of permits – Mutex – mutual exclusion semaphore or binary semaphore • Similar to locks but allow release from different thread – useful in deadlock recovery

• CyclicBarrier – Reusable barrier for a group of threads – Maybe used with a timeout

• CountdownLatch – Similar to barrier but not reusable – Separates barrier arrival from waiting – Can be used as a starting gate

• Exchanger – Rendezvous – Similar to a barrier of two but with data exchange

CIT Concurrency

Readers/Writers (1) • A shared database is accessed by two kinds of processes. Readers execute transactions that examine the database while Writers both examine and update the database. A Writer must have exclusive access to the database; any number of Readers may concurrently access it.

Light blue indicates database access.

CIT Concurrency

Readers/Writers (2) • We concentrate on the monitor implementation • We define an interface that identifies the monitor methods that must be implemented, and develop a number of alternative implementations of this interface. – Firstly, the safe READWRITELOCK. interface ReadWrite { public void acquireRead() throws InterruptedException; public void releaseRead(); public void acquireWrite() throws InterruptedException; public void releaseWrite(); }

Readers/Writers (3)

CIT Concurrency

class ReadWriteSafe implements ReadWrite { private int readers =0; private boolean writing = false; public synchronized void acquireRead() throws InterruptedException { while (writing) wait(); ++readers; } public synchronized void releaseRead() { --readers; if(readers==0) notify(); } Unblock a single writer when no more readers.

Readers/Writers (4)

CIT Concurrency

public synchronized void acquireWrite() throws InterruptedException { while (readers>0 || writing) wait(); writing = true; } public synchronized void releaseWrite() { writing = false; notifyAll(); } }

Unblock all readers

This monitor implementation suffers from the WRITE progress problem: possible writer starvation if the number of readers never drops to zero.

Strategy: Block readers if there is a writer waiting.

CIT Concurrency

Readers/Writers (5) class ReadWritePriority implements ReadWrite{ private int readers =0; Both READ private boolean writing = false; private int waitingW = 0; // no of waiting Writers. and WRITE progress public synchronized void acquireRead() properties throws InterruptedException can be { while (writing || waitingW>0) wait(); satisfied by ++readers; } introducing public synchronized void releaseRead() a turn { --readers; if (readers==0) notify(); } variable as synchronized public void acquireWrite() in the { ++waitingW; Single Lane while (readers>0 || writing) try{ wait();} Bridge. catch(InterruptedException e){} --waitingW; writing = true; } synchronized public void releaseWrite() { writing = false; notifyAll(); } }

Low-Level facilities • Locks

CIT Concurrency

– Lock interface – Like the syncrhonized lock but with variations • Timed waits, interruptible waits, lock polling, multiple condition wait sets per lock, non-blocking structured locking

– Reentrant lock implements interface • More scalable than synchronised • But, requires explicit unlocking

– Condition interface • Generalisation of wait()/notify() • Multiple conditions on the same lock

– ReadWriteLock – Can be fair, but fairness doesn’t scale

• Atomic variables – AtomicInteger/Long/Boolean/etc.