Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Session 1 - Java Concurrency I

Session 1 - Java Concurrency I

Speakers: Alex Vazquez and Guillermo Muñoz
Topics:
- Introduction to Java Concurrency Framework (JCF)
- Analysis of issues without using JCF
- Review of concurrent collections in JCF
- Review of Lock implementation

Avatar for javatroopers

javatroopers

August 09, 2012
Tweet

More Decks by javatroopers

Other Decks in Programming

Transcript

  1. What is Concurrency? • In a computer system, concurrency is

    the situation where a set of resources are being accessed at the same time by multiple executing programs. 2
  2. How is it done in Java? • Multiple ways to

    do it. • Thread instances + Runnable implementations class MyTask implements Runnable { @Override public void run() { // do whatever is needed } } Thread t = new Thread(new MyTask()); t.start(); Thread t = new Thread(new Runnable() { @Override public void run() { // do whatever is needed } }); t.start(); 3
  3. Concurrency issues • Concurrency issues rise when one thread of

    execution is accessing the same resources (variables, files, network connections, etc) at the same time, disregarding other threads that may use the same resources. public int foo; while(crazyCondition()) { weirdStuff(); if(++foo > MAX_VALUE) { foo = 0; } } if(someOtherCrazyCondition()) { if(--foo < 0) { foo = MAX_VALUE; } } 4
  4. Concurrency issues “resolved” • synchronized is a tool to define

    mutual exclusions between otherwise unrelated code. The exclusion is based on any given object instance. private Object that = new Object(); private int foo; while(crazyCondition()) { weirdStuff(); synchronized(that) { if(++foo > MAX_VALUE) { foo = 0; } } } if(someOtherCrazyCondition()) { synchronized(that) { if(--foo < 0) { foo = MAX_VALUE; } } } 5
  5. Synchronization scenarios • Memory caches • Exclusive access to memory

    cache. • Readers-Writers • Simultaneous access to read-only processes • Exclusive access for write processes • Producers-Consumers • Coordinated production and consumption of resources. 6
  6. Coordinated synchronization • wait() and notify() • wait() suspends a

    thread holding a lock until another thread tells it “something” happened. • notify() schedules a waiting thread to be awaken due to “that something” happening. 7
  7. Coordinated producer-consumer Producer thread Consumer thread Produce element Space avail?

    Wait for notification… Place element Notify others No Yes Consume element Element avail? Wait for notification… Take element Notify others No Yes 8
  8. Two-threaded producer-consumer private Integer elem = null; while(true) { int

    value = producer.produce(); synchronized(this) { while(elem != null) { try { wait(); } catch(InterruptedException ex) { } } elem = value; notify(); log("produced: " + value); } } while(true) { int value; synchronized(this) { while(elem == null) { try { wait(); } catch(InterruptedException ex) { } } value = elem; elem = null; notify(); log("consumed:" + value); } consumer.consume(value); } Producer thread Consumer thread 9
  9. Two-threaded producer-consumer private Integer elem = null; while(true) { int

    value = producer.produce(); synchronized(this) { while(elem != null) { try { wait(); } catch(InterruptedException ex) { } } elem = value; notify(); log("produced: " + value); } } while(true) { int value; synchronized(this) { while(elem == null) { try { wait(); } catch(InterruptedException ex) { } } value = elem; elem = null; notify(); log("consumed:" + value); } consumer.consume(value); } Producer thread Consumer thread 10
  10. Multiple-thread producer-consumers private Integer elem = null; while(true) { int

    value = producer.produce(); synchronized(this) { while(elem != null) { try { wait(); } catch(InterruptedException ex) { } } elem = value; notify(); log("produced: " + value); } } while(true) { int value; synchronized(this) { while(elem == null) { try { wait(); } catch(InterruptedException ex) { } } value = elem; elem = null; notify(); log("consumed:" + value); } consumer.consume(value); } Producer thread Consumer thread while(true) { int value; synchronized(this) { while(elem == null) { try { wait(); } catch(InterruptedException ex) { } } value = elem; elem = null; notify(); log("consumed:" + value); } consumer.consume(value); } Consumer thread ? ? 11
  11. Multiple-thread producer-consumers private Integer elem = null; while(true) { int

    value = producer.produce(); synchronized(this) { while(elem != null) { try { wait(); } catch(InterruptedException ex) { } } elem = value; notify(); log("produced: " + value); } } while(true) { int value; synchronized(this) { while(elem == null) { try { wait(); } catch(InterruptedException ex) { } } value = elem; elem = null; notify(); log("consumed:" + value); } consumer.consume(value); } Producer thread Consumer thread while(true) { int value; synchronized(this) { while(elem == null) { try { wait(); } catch(InterruptedException ex) { } } value = elem; elem = null; notify(); log("consumed:" + value); } consumer.consume(value); } Consumer thread ? ? 12
  12. Multiple-thread producer-consumers private Integer elem = null; while(true) { int

    value = producer.produce(); synchronized(this) { while(elem != null) { try { wait(); } catch(InterruptedException ex) { } } elem = value; notifyAll(); log("produced: " + value); } } while(true) { int value; synchronized(this) { while(elem == null) { try { wait(); } catch(InterruptedException ex) { } } value = elem; elem = null; notifyAll(); log("consumed:" + value); } consumer.consume(value); } Producer thread Consumer thread while(true) { int value; synchronized(this) { while(elem == null) { try { wait(); } catch(InterruptedException ex) { } } value = elem; elem = null; notifyAll(); log("consumed:" + value); } consumer.consume(value); } Consumer thread 14
  13. Java Concurrency Framework (JCF) • JCF = (Thread-safe + Well-tested

    + High-performance) * Concurrent building blocks • Since JDK 5 under java.util.concurrent package, thanks to Doug Lea. • Goal: (Collections framework -> Data structures) = (JCF -> Concurrent programming) • No more: synchronized, Object.wait(), Object.notify[All](), Thread.join(), Thread.sleep(), Vector, Hashtable, Collections.synchronized* wrappers. 15
  14. JCF components • Tasks Management: Callable<V>, Future<V>, Executor, ExecutorService (Thread

    pools), etc. • Concurrent collections: ConcurrentHashMap, CopyOnWriteArray[List| Set], Blocking Queues. • Synchronization utilities: Semaphore, CyclicBarrier, CountDownLatch, Exchanger. • Low-level facilities: Lock, ReentrantLock, ReadWriteLock, Atomic variables. 16
  15. Concurrent collections • < JDK 5 Collections • JUC Collections

    • Improved scalability: less locks = more concurrent threads • Weakly-consistent iterators: snapshots = no more ConcurrentModificationException • Built-in composite ops: no unexpected race conditions. Problem Consequence Workaround One lock per collection Long waits None Fail-fast iterators ConcurrentModificationException Create a local copy No composite-ops Race conditions Use synchronized blocks 17
  16. CopyOnWriteArray[List|Set] • Underlying array (volatile = visibility) • Mutative ops

    over underlying array (add, set, remove, etc) using ReentrantLock • Be careful: literally copy all the array • Snapshot style iterator: no changes to original array (read-only) • Use when: • Reads >> writes • Small number of elements • Better performance than: Vector, Collections.synchronized[List|Set]() 18
  17. ConcurrentHashMap • Multiple concurrent writers and readers • Built-in atomic

    ops: putIfAbsent(key, value), replace(key, [oldValue,] value) and remove(key, value). • Weakly-consistent iterators: removal ops backed by map, best-effort to reflect adds • Flexible concurrency rate: concurrencyLevel in constructor = # of segments • Be careful: more segments = waste space, less segments = thread contention. • Better performance than: Hastable or Collections.synchronizedMap() 19
  18. Blocking Queues • Designed for producer-consumer queues. • take() blocks

    until to non-empty queue, put() blocks until space to store. Blocking queue Capacity Backed by SynchronousQueue Bounded (1) E ArrayBlockingQueue Bounded E[] LinkedBlockingQueue Bounded | Unbounded Node<E> linked list PriorityBlockingQueue Unbounded PriorityQueue<E> DelayQueue Unbounded PriorityQueue<Delayed> 20
  19. java.util.concurrency.locks • Defines a mutual execution lock, detached from Object

    abstraction • Specializes in process synchronization and coordination • Provides enhanced semantics • Introduces the Conditions, which enable to signal separate thread notification when specific conditions are being waited for. 21
  20. How to use j.u.c.Locks? import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;

    /* ... */ Lock lock = new ReentrantLock(); Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); 22
  21. Lock Semantics Object synchronization Lock synchronization synchronized(object) { // do

    something } lock.lock(); try { // do something } finally { lock.unlock(); } try { object.wait(); } catch(InterruptedException ie) { // pretend to do something } condition.awaitUninterruptibly(); object.notify(); condition.signal(); 23
  22. private Integer elem = null; private Lock lock = new

    ReentrantLock(); private Condition placed = lock.newCondition(); private Condition taken = lock.newCondition(); Producer thread Consumer thread while(true) { int prime = producer.produce(); lock.lock(); try { while(elem != null) { taken.awaitUninterruptibly(); } elem = prime; placed.signal(); log("produced: " + prime); } finally { lock.unlock(); } } while(true) { int value; lock.lock(); try { while(elem == null) { placed.awaitUninterruptibly(); } value = elem; elem = null; taken.signal(); log("consumed:" + value); } finally { lock.unlock(); } consumer.consume(value); } 24
  23. private Integer elem = null; private Lock lock = new

    ReentrantLock(); private Condition placed = lock.newCondition(); private Condition taken = lock.newCondition(); Producer thread Consumer thread while(true) { int prime = producer.produce(); lock.lock(); try { while(elem != null) { taken.awaitUninterruptibly(); } elem = prime; placed.signal(); log("produced: " + prime); } finally { lock.unlock(); } } while(true) { int value; lock.lock(); try { while(elem == null) { placed.awaitUninterruptibly(); } value = elem; elem = null; taken.signal(); log("consumed:" + value); } finally { lock.unlock(); } consumer.consume(value); } 25
  24. Producer thread Consumer thread while(true) { int prime = producer.produce();

    lock.lock(); try { while(elem != null) { taken.awaitUninterruptibly(); } elem = prime; placed.signal(); log("produced: " + prime); } finally { lock.unlock(); } } while(true) { int value; lock.lock(); try { while(elem == null) { placed.awaitUninterruptibly(); } value = elem; elem = null; taken.signal(); log("consumed:" + value); } finally { lock.unlock(); } consumer.consume(value); } Consumer thread while(true) { int value; lock.lock(); try { while(elem == null) { placed.awaitUninterruptibly(); } value = elem; elem = null; taken.signal(); log("consumed:" + value); } finally { lock.unlock(); } consumer.consume(value); } ? 26
  25. Producer thread Consumer thread while(true) { int prime = producer.produce();

    lock.lock(); try { while(elem != null) { taken.awaitUninterruptibly(); } elem = prime; placed.signal(); log("produced: " + prime); } finally { lock.unlock(); } } while(true) { int value; lock.lock(); try { while(elem == null) { placed.awaitUninterruptibly(); } value = elem; elem = null; taken.signal(); log("consumed:" + value); } finally { lock.unlock(); } consumer.consume(value); } Consumer thread while(true) { int value; lock.lock(); try { while(elem == null) { placed.awaitUninterruptibly(); } value = elem; elem = null; taken.signal(); log("consumed:" + value); } finally { lock.unlock(); } consumer.consume(value); } 27