SlideShare a Scribd company logo
Java Concurrency Idioms

         Alex Miller
Sharing



          Signals



 Work
Sharing
Data Race!


    A
Unsafe access
NOT safe for multi-threaded access:

public interface Counter
{
    int increment();
}


public class UnsafeCounter implements Counter {
    private int c = 0;

    public int increment() {
        return c++;
    }
}
volatile
Is this safe?


public class VolatileCounter implements Counter
{
    private volatile int c = 0;

    public int increment() {
        return c++;
    }
}
Synchronization


       A
synchronized


public class SynchronizedCounter
   implements Counter {

    private int c = 0;

    public synchronized int increment() {
        return c++;
    }
}
Atomic classes


public class AtomicCounter implements Counter
{
    private final AtomicInteger c =
                         new AtomicInteger(0);

    public int increment() {
        return c.incrementAndGet();
    }
}
ReentrantLock
public class ReentrantLockCounter
implements Counter
{
    private final Lock lock = new ReentrantLock();
    private int c = 0;

    public int increment() {
        lock.lock();
        try {
          return c++;
        } finally {
          lock.unlock();
        }
    }
}
ReentrantReadWriteLock
public class ReentrantRWLockCounter implements Counter {
    private final ReadWriteLock lock =
                             new ReentrantReadWriteLock();
    private int c = 0;
    public int increment() {
        lock.writeLock().lock();
        try {
          return c++;
        } finally {
          lock.writeLock().unlock();
        }
    }

    public int read() {
        lock.readLock().lock();
        try {
            return c;
        } finally {
            lock.readLock().unlock();
        }
    }
}
Encapsulation

 B

      A
Immutability

     A




     B
Immutability
Make field final, “mutator” methods return new
immutable instances.

public class Speed
{
    private final int milesPerHour;

    public Speed(int milesPerHour) {
       this.milesPerHour = milesPerHour;
    }

    public Speed sawCop() {
        return new Speed(this.milesPerHour - 10);
    }
}
Thread Confinement

        A




        B
ThreadLocal
ThreadLocal gives every Thread its own instance,
so no shared state.
public class ThreadLocalCounter implements Counter
{
    private final ThreadLocal<Integer> count =
      new ThreadLocal<Integer>();

    public ThreadLocalCounter() {
        count.set(Integer.valueOf(0));
    }

    public int increment() {
        Integer c = count.get();
        int next = c.intValue() + 1;
        count.set(Integer.valueOf(next));
        return next;
    }
}
code.run()
2 threads, 10000 reps
                  3,000


                  2,250
Total time (ms)




                  1,500


                   750


                     0
                          0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%
                                              Write %

                          sychronized   RL(false)         RL(true)
                          RRWL(false)   RRWL(true)        synchronizedMap
                          Concurrent
2 threads, 10000 reps
                  130.0


                   97.5
Total time (ms)




                   65.0


                   32.5


                     0
                          0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%
                                              Write %

                          sychronized         RL(false)         RRWL(false)
                          synchronizedMap     Concurrent
Signals
Direct Thread Interaction

         join()
join()
join() waits for another Thread to exit - signaling by
completion

Thread[] threads = new Thread[THREADS];

// start threads doing stuff

// wait for completion
for(int i=0; i<THREADS; i++) {
    threads[i].join();
}
Wait / Notify

notify()        wait()

           A
wait()
- wait() must occur in synchronization
- should occur in loop on the wait condition

synchronized(lock) {
    while(! someCondition) {
        lock.wait();
    }
}
notify() / notifyAll()
- notify() / notifyAll() must occur in synchronization



synchronized(lock) {
    lock.notifyAll();
}
Conditions

signal()               await()

           Condition
Condition waiting
Same as wait/notify but more flexible



Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();

// wait
lock.lock();
try {
    while(! theCondition) {
        condition.await(1, TimeUnit.SECONDS);
    }
} finally {
    lock.unlock();
}
Condition signaling


Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();

// wait
lock.lock();
try {
    condition.signalAll();
} finally {
    lock.unlock();
}
CyclicBarrier

                          N:
                await()
   Cyclic
   Barrier(N)
CyclicBarrier
Wait for known # of threads to reach barrier, then
release. Can be used multiple times.

int THREADS = 5;
CyclicBarrier barrier = new CyclicBarrier(THREADS);

// in thread, wait to start
barrier.await();

// do stuff

// in thread, wait to stop
barrier.await();
CountDownLatch

N:                                       M:
                               await()
     countDown()   CountDown
                   Latch(N)
CountDownLatch
Threads wait for count to reach 0



int COUNT = 5;
CountDownLatch latch = new CountDownLatch(COUNT);

// count down
latch.countDown();

// wait
latch.await();
code.run()
Work
Thread Pools
Queues



 ...
ExecutorService
ExecutorService
Executors has helper methods to create different
kinds of ExecutorServices backed by thread pools

// Create service backed by thread pool
ExecutorService service =
  Executors.newFixedThreadPool(THREADS);

// Define a Work that is Runnable
class Work implements Runnable {...}

// Submit work to the thread pool
service.execute(new Work());
CompletionService
CompletionService
CompletionService combines an ExecutorService
with a completion queue.

// Create completion service backed by thread pool
ExecutorService executor =
    Executors.newFixedThreadPool(THREADS);
CompletionService<Integer> completionService =
    new ExecutorCompletionService<Integer>(executor);

// Submit work
completionService.submit(
    new Callable<Integer>() { .. } );

// Wait for a result to be available
Future<Integer> result = completionService.take();
Integer value = result.get();   // blocks
code.run()
Questions?


Sharing



           Signals


 Work
Blog: http://tech.puredanger.com

Job: http://terracotta.org

Twitter: http://twitter.com/puredanger




                                         All content © 2008 by Alex Miller
                                         Photos from iStockPhoto.com

More Related Content

Java Concurrency Idioms

  • 2. Sharing Signals Work
  • 5. Unsafe access NOT safe for multi-threaded access: public interface Counter { int increment(); } public class UnsafeCounter implements Counter { private int c = 0; public int increment() { return c++; } }
  • 6. volatile Is this safe? public class VolatileCounter implements Counter { private volatile int c = 0; public int increment() { return c++; } }
  • 8. synchronized public class SynchronizedCounter implements Counter { private int c = 0; public synchronized int increment() { return c++; } }
  • 9. Atomic classes public class AtomicCounter implements Counter { private final AtomicInteger c = new AtomicInteger(0); public int increment() { return c.incrementAndGet(); } }
  • 10. ReentrantLock public class ReentrantLockCounter implements Counter { private final Lock lock = new ReentrantLock(); private int c = 0; public int increment() { lock.lock(); try { return c++; } finally { lock.unlock(); } } }
  • 11. ReentrantReadWriteLock public class ReentrantRWLockCounter implements Counter { private final ReadWriteLock lock = new ReentrantReadWriteLock(); private int c = 0; public int increment() { lock.writeLock().lock(); try { return c++; } finally { lock.writeLock().unlock(); } } public int read() { lock.readLock().lock(); try { return c; } finally { lock.readLock().unlock(); } } }
  • 14. Immutability Make field final, “mutator” methods return new immutable instances. public class Speed { private final int milesPerHour; public Speed(int milesPerHour) { this.milesPerHour = milesPerHour; } public Speed sawCop() { return new Speed(this.milesPerHour - 10); } }
  • 16. ThreadLocal ThreadLocal gives every Thread its own instance, so no shared state. public class ThreadLocalCounter implements Counter { private final ThreadLocal<Integer> count = new ThreadLocal<Integer>(); public ThreadLocalCounter() { count.set(Integer.valueOf(0)); } public int increment() { Integer c = count.get(); int next = c.intValue() + 1; count.set(Integer.valueOf(next)); return next; } }
  • 18. 2 threads, 10000 reps 3,000 2,250 Total time (ms) 1,500 750 0 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100% Write % sychronized RL(false) RL(true) RRWL(false) RRWL(true) synchronizedMap Concurrent
  • 19. 2 threads, 10000 reps 130.0 97.5 Total time (ms) 65.0 32.5 0 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100% Write % sychronized RL(false) RRWL(false) synchronizedMap Concurrent
  • 22. join() join() waits for another Thread to exit - signaling by completion Thread[] threads = new Thread[THREADS]; // start threads doing stuff // wait for completion for(int i=0; i<THREADS; i++) { threads[i].join(); }
  • 24. wait() - wait() must occur in synchronization - should occur in loop on the wait condition synchronized(lock) { while(! someCondition) { lock.wait(); } }
  • 25. notify() / notifyAll() - notify() / notifyAll() must occur in synchronization synchronized(lock) { lock.notifyAll(); }
  • 26. Conditions signal() await() Condition
  • 27. Condition waiting Same as wait/notify but more flexible Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); // wait lock.lock(); try { while(! theCondition) { condition.await(1, TimeUnit.SECONDS); } } finally { lock.unlock(); }
  • 28. Condition signaling Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); // wait lock.lock(); try { condition.signalAll(); } finally { lock.unlock(); }
  • 29. CyclicBarrier N: await() Cyclic Barrier(N)
  • 30. CyclicBarrier Wait for known # of threads to reach barrier, then release. Can be used multiple times. int THREADS = 5; CyclicBarrier barrier = new CyclicBarrier(THREADS); // in thread, wait to start barrier.await(); // do stuff // in thread, wait to stop barrier.await();
  • 31. CountDownLatch N: M: await() countDown() CountDown Latch(N)
  • 32. CountDownLatch Threads wait for count to reach 0 int COUNT = 5; CountDownLatch latch = new CountDownLatch(COUNT); // count down latch.countDown(); // wait latch.await();
  • 34. Work
  • 38. ExecutorService Executors has helper methods to create different kinds of ExecutorServices backed by thread pools // Create service backed by thread pool ExecutorService service = Executors.newFixedThreadPool(THREADS); // Define a Work that is Runnable class Work implements Runnable {...} // Submit work to the thread pool service.execute(new Work());
  • 40. CompletionService CompletionService combines an ExecutorService with a completion queue. // Create completion service backed by thread pool ExecutorService executor = Executors.newFixedThreadPool(THREADS); CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(executor); // Submit work completionService.submit( new Callable<Integer>() { .. } ); // Wait for a result to be available Future<Integer> result = completionService.take(); Integer value = result.get(); // blocks
  • 42. Questions? Sharing Signals Work
  • 43. Blog: http://tech.puredanger.com Job: http://terracotta.org Twitter: http://twitter.com/puredanger All content © 2008 by Alex Miller Photos from iStockPhoto.com