JavaConcurrencyRahul RevoGarrett Short<br />Creative Mindays<br />March 3, 2011<br />
Why care about Concurrency<br />The free lunch is over – Herb Sutter<br />Multi-core processors are here<br />Applications...
Language support for concurrency<br />Threads – C, C++, Java …<br />Actors – Erlang<br />Single thread and WebWorker - Jav...
Thread safe code 1<br />Manage access to shared mutable data<br />Why<br />Order of execution<br />Stale data visible<br /...
Thread safe code        2<br />Manage access to shared mutable data<br />How<br />Don’t share state variables across threa...
volatile<br />Reads and writes provide correct visibility<br />Happens-before relationship, like a synchronized block<br /...
Immutable Objects<br />An object is immutable if<br />State cannot be modified after construction<br />All fields are fina...
Annotations<br />@GuardedBy(“some-lock-or-var”)<br />The field or method can only be accessed when holding a particular lo...
java.util.concurrent<br />Collections<br />BlockingQueue<br />ConcurrentMap<br />CopyOnWrite<br />Task Execution<br />Exec...
Consumer:<br />synchronized (obj) {<br />    while (! workToDo) {<br />obj.wait();<br />    }<br />    // get next item fr...
class Producer implements Runnable {<br />   private final BlockingQueue queue;<br />   Producer(BlockingQueue q) { queue ...
class Consumer implements Runnable {<br />   private final BlockingQueue queue;<br />   Consumer(BlockingQueue q) { queue ...
13<br />3 March 2011<br />void main() {<br />BlockingQueue q = new SomeQueueImplementation();<br />  Producer p = new Prod...
Concurrent HashMap1<br />Completely plug-compatible, implements the same Map interface we all know and love today.<br />Al...
Concurrent HashMap2<br />Add an item in a hash map only if it doesn’t already exist<br /><ul><li>Old way:</li></ul>synchro...
Concurrent 3<br />Additional methods beyond HashMap<br />boolean remove(Object key, Object value)If this key is mapped to ...
CopyOnWriteArrayList<br />CopyOnWriteArrayList makes a  fresh copy of the underlying array for mutative operations like ad...
Collection Classes<br />Do not use the old synchronized classes:<br />Vector, Stack, Hashtable<br />Use the non-synchroniz...
Task Execution     1<br />Decouple the task submission from task execution by using an Executor<br />Define an execution p...
Task Execution                                   2<br />20<br />3 March 2011<br />class ThreadPerTaskExecutor implements E...
ExecutorService<br />Methods provided for shutdown<br />Get status of tasks via Future<br />ExecutorService extends Execut...
What’s the Future<br />Callable – Runnable on steroidsCallable<V> {  V call() throws Exception;}<br />Future – result of a...
Asynchronous results<br />class QuoteProcessor {<br />ExecutorService exec = ...<br />processQuotes() {<br />    List<Quot...
Scheduled Processing<br />Use ScheduledThreadPoolExecutor instead of java.util.Timer<br />executor = new ScheduledThreadPo...
ThreadPoolExecutor<br />ThreadPoolExecutor configurations<br />Core and maximum pool <br />On-demand construction<br />Cre...
More concurrent APIs<br />Locks<br />Condition<br />Lock<br />ReadWriteLock<br />ReentrantLock<br />Atomic<br />Boolean, l...
Fork Join (coming in JDK 7)<br />The fork/join framework is designed to make divide-and-conquer algorithms easy to paralle...
Fork Join Example<br />class ForkJoinMain {<br />    main() {<br />ForkJoinPool pool = new ForkJoinPool();<br />int[] data...
Fork Join Example<br />abstract class AbstractExampleTask extends RecursiveTask<Long> {<br />AbstractExampleTask(int[] dat...
class SumSquaresTask extends AbstractExampleTask {<br />SumSquaresTask(...) { ... }<br />    Long directlySolve() {<br /> ...
Summary<br />Recommended order of use<br />Use high level java.util.concurrent APIs<br />Low level locking with synchroniz...
Q&A<br />32<br />3 March 2011<br />
Upcoming SlideShare
Loading in …5
×

Concurrent talk

1,222 views

Published on

Published in: Technology
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,222
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
0
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide
  • http://www.gotw.ca/publications/concurrency-ddj.htmApplications will increasingly need to be concurrent if they want to fully exploit continuing exponential CPU throughput gainsEfficiency and performance optimization will get more, not less, importanthttp://www.infoq.com/interviews/pike-concurrency Concurrency is a programming model that lets you express things that are independent, as independent executions and parallelism is about running two things at the same time. They are not the same idea and a lot of people confuse them, they think they are the same thing, but concurrency and parallelism are best thought of as a different idea. You can write beautiful concurrent programs with no parallelism whatsoever and you can also write extremely parallel programs that are not remotely concurrent. Concurrency is a model, parallelism is a result - maybe that&apos;s the best way to say it.
  • Different programming languages support concurrent programming in different waysThreading libraries, actor framework, no explicit threads!Thread is a unit of executionMultiple threads can be running at the same timeMonitors allow a single thread to be running inside a critical areaCommunicate by wait/notify mechanismAnd we’ll talk mainly about the new APIs
  • Happens-beforeVisibilityCompilers can reorder codePage 341
  • Page 54
  • If cancelled is not volatile then the cancel set by another thread may never be visible
  • Transfer of ownership of the thoseItemsCan have a copy strategy if returning something modifiable
  • Writing multiple-threaded code is hardDebugging m-t code is hardedDebugging someone elses m-t code is even harder.So little documentation can go a long way to help.Help both you and the reader.Documentationof your sync policyCan download a jar that defines these annotations
  • Avoid creating your own locks and synchronization blocks.Get out of the business of creating your own threads and managing their life cycle.
  • Here’s the old way of doing a producer/consumer pattern.This creates a synchronized block around the management of a work queue and a Boolean control flag ----- Ugly and MessyMight have the ‘while’ as just and ‘if’Might be some code outside the synchronized blocks that messing with the queue, hard to be absolutely sure.
  • Blocking Queue -- Waits for the queue to be non-empty when retrieving objects and waits for storage available when adding objects.Maybe capacity bounded.
  • See how much cleaner and simpler this code is.
  • There are 4-5 new classes that implement the BlockingQueue interface. Pick one that best suits your needs.So no messy obj synchronization, no calls to wait/notify.
  • HashMaps are very common in code dealing with a large number of objects.If you are writing m-t code, consider a concurrent hash map.
  • The concurrent hash map goes beyond the simple HashMap class with some useful methods, here’s one example.Even if the map was synchronize, you still need to create a synchronize block around compound calls.
  • More compound operations combined in a single method.
  • list should be used when the number of reads vastly outnumber the number of writes. This is because you are trading unnecessary synchronization for expensive array copying on each write.Here’s the problem: You have a collection with lots of readers and a few writers operating in a multi-thread environment. Two solutions: writers wait until it can gain exclusive access, or readers make a copy of the collection first.Here’s an example.Caveat: the readers may be operating on stale data. Mostly likely it doesn’t matter.
  • Didn’t make JDK 6, based on JSR 166.Library (jsr166.jar) is available today.
  • Here’s the problem:You have a huge data set that need to be processed. You want to gain performance by having multiple threads doing the computation.
  • http://video.google.com/videoplay?docid=8394326369005388010http://www.javaconcurrencyinpractice.com/Effective java
  • Concurrent talk

    1. 1. JavaConcurrencyRahul RevoGarrett Short<br />Creative Mindays<br />March 3, 2011<br />
    2. 2. Why care about Concurrency<br />The free lunch is over – Herb Sutter<br />Multi-core processors are here<br />Applications need to be concurrent to exploit CPUs<br />March 2005 http://www.gotw.ca/publications/concurrency-ddj.htm<br />2<br />3 March 2011<br />
    3. 3. Language support for concurrency<br />Threads – C, C++, Java …<br />Actors – Erlang<br />Single thread and WebWorker - Javascript<br />Java<br />Threading support in core library<br />Monitor based synchronization<br />and new concurrency APIs<br />3<br />3 March 2011<br />
    4. 4. Thread safe code 1<br />Manage access to shared mutable data<br />Why<br />Order of execution<br />Stale data visible<br />Atomicity<br />4<br />3 March 2011<br />x= y = 0<br />Thread 1<br />Thread 2<br />y = 1<br /> j = x<br />x = 1i = y<br />Can i = 0 and j = 0 ?<br />
    5. 5. Thread safe code 2<br />Manage access to shared mutable data<br />How<br />Don’t share state variables across threads<br />Use java.lang.ThreadLocal<br />Make objects immutable<br />Guard access<br />5<br />3 March 2011<br />
    6. 6. volatile<br />Reads and writes provide correct visibility<br />Happens-before relationship, like a synchronized block<br />class Worker implements Runnable {<br /> private volatileboolean cancelled = false;<br /> run() {<br /> while(!cancelled) { //do work }<br /> }<br /> cancel() { cancelled = true; }<br />}<br />6<br />3 March 2011<br />
    7. 7. Immutable Objects<br />An object is immutable if<br />State cannot be modified after construction<br />All fields are final<br />this reference does not escape during construction<br />7<br />3 March 2011<br />class Cart {<br /> private List<String> items;<br /> public Cart(List items) { this.items = items; }<br /> public List getItems() { return items; }<br />}<br />class ImmutableCart {<br /> private final List<String> items;<br /> public ImmutableCart(List<String> thoseItems) {<br /> items = Collections.unmodifiableList(new ArrayList<>(thoseItems));<br /> }<br /> public List getItems() { return items; }<br />}<br />
    8. 8. Annotations<br />@GuardedBy(“some-lock-or-var”)<br />The field or method can only be accessed when holding a particular lock<br />@Immutable<br />Its state cannot be seen to change by callers<br />@NotThreadSafe<br />Clarifying the non-thread-safety of a class that might otherwise be assumed to be thread-safe<br />@ThreadSafe<br />This means that no sequences of accesses may put the object into an invalid state, regardless of the interleaving of those actions without requiring any additional synchronization on the part of the caller.<br />8<br />3 March 2011<br />
    9. 9. java.util.concurrent<br />Collections<br />BlockingQueue<br />ConcurrentMap<br />CopyOnWrite<br />Task Execution<br />Executor, ExecutorService<br />Executors<br />Callable<br />Future<br />9<br />3 March 2011<br />
    10. 10. Consumer:<br />synchronized (obj) {<br /> while (! workToDo) {<br />obj.wait();<br /> }<br /> // get next item from the queue<br />workToDo = false; <br />}<br />// do work on the item<br />Producer:<br />synchronized (obj) {<br /> if (! workToDo) {<br /> // add work to queue<br />workToDo = true;<br /> }<br />obj.notifyAll();<br />}<br />10<br />3 March 2011<br />Producer-Consumer Pattern 1<br />
    11. 11. class Producer implements Runnable {<br /> private final BlockingQueue queue;<br /> Producer(BlockingQueue q) { queue = q; }<br /> public void run() {<br /> while (true) {<br />queue.put(produce()); <br /> }<br /> }<br /> private Object produce() { ... }<br /> }<br />11<br />3 March 2011<br />Producer-Consumer Pattern 3<br />
    12. 12. class Consumer implements Runnable {<br /> private final BlockingQueue queue;<br /> Consumer(BlockingQueue q) { queue = q; }<br /> public void run() {<br /> while (true) {<br />consume(queue.take());<br /> }<br /> }<br /> private void consume(Object x) { ... }<br /> }<br />12<br />3 March 2011<br />Producer-Consumer Pattern 4<br />
    13. 13. 13<br />3 March 2011<br />void main() {<br />BlockingQueue q = new SomeQueueImplementation();<br /> Producer p = new Producer(q);<br /> Consumer c1 = new Consumer(q);<br /> Consumer c2 = new Consumer(q);<br /> new Thread(p).start();<br /> new Thread(c1).start();<br /> new Thread(c2).start();<br />}<br />Producer-Consumer Pattern 2<br />
    14. 14. Concurrent HashMap1<br />Completely plug-compatible, implements the same Map interface we all know and love today.<br />All operations are thread-safe, however retrieval operations do not involve locking the entire table. <br />No ConcurrentModificationException! Creation of the an iterator or some enumeration reflect the state at that time. Note: iterators are intended to be used by only one thread at a time. <br />Resizing is relatively slow operation, so try to provide good estimates of expected table sizes in constructors. <br />A new optional 'concurrencyLevel' constructor argument (default 16), which is used as a hint for internal sizing. The value is the estimated number of concurrent updating threads. A value of 1 is appropriate there is only one writer and all other threads are readers. <br />14<br />3 March 2011<br />
    15. 15. Concurrent HashMap2<br />Add an item in a hash map only if it doesn’t already exist<br /><ul><li>Old way:</li></ul>synchronize (obj) {if (! map.containsKey(key)) {map.put(key, value);}<br />}<br /><ul><li>New Way:</li></ul>map.putIfAbsent(key, value);<br />15<br />3 March 2011<br />
    16. 16. Concurrent 3<br />Additional methods beyond HashMap<br />boolean remove(Object key, Object value)If this key is mapped to this value, remove it.<br />V replace(K key, V value)If this key is mapped to any value, then map it instead to this new value. <br />booleanreplace(K key, V oldValue, V newValue)If this key is mapped to this old value, then map it to this new value.<br />16<br />3 March 2011<br />
    17. 17. CopyOnWriteArrayList<br />CopyOnWriteArrayList makes a  fresh copy of the underlying array for mutative operations like add<br />Use when lots of reads vs writes like event listeners<br />List list1 = new CopyOnWriteArrayList(...);<br />List list2 = new ArrayList(...);<br />Iterator itor1 = list1.iterator();<br />Iterator itor2 = list2.iterator();<br />list1.add("New");<br />list2.add("New");<br />printAll(itor1);<br />printAll(itor2); // throws ConcurrentModificationException<br />17<br />3 March 2011<br />
    18. 18. Collection Classes<br />Do not use the old synchronized classes:<br />Vector, Stack, Hashtable<br />Use the non-synchronized version when that’s all you need:<br />Arraylist, LinkedList, HashMap<br />When Synchronization is needed, use the new java.util.concurrentclasses:<br />ArrayBlockingQueue, LinkedBlockingQueue, ConcurrentHashMap<br />18<br />3 March 2011<br />
    19. 19. Task Execution 1<br />Decouple the task submission from task execution by using an Executor<br />Define an execution policy<br />In what thread will execution happen<br />What is the order of execution <br />How many tasks run concurrently<br />19<br />3 March 2011<br />
    20. 20. Task Execution 2<br />20<br />3 March 2011<br />class ThreadPerTaskExecutor implements Executor { public void execute(Runnable r) { new Thread(r).start(); }}<br />class DirectExecutor implements Executor { public void execute(Runnable r) {r.run(); } }<br />Executor executor = anExecutor; executor.execute(new Runnable1());<br />executor.execute(new Runnable2());<br />And...<br />FixedThreadPool<br />CachedThreadPool<br />ScheduledThreadPool<br />
    21. 21. ExecutorService<br />Methods provided for shutdown<br />Get status of tasks via Future<br />ExecutorService extends Executor { void execute(Runnable r); Future<T> submit(Callable<T> t …); void shutdown();booleanisShutdown();booleanisTerminated();}<br />21<br />3 March 2011<br />
    22. 22. What’s the Future<br />Callable – Runnable on steroidsCallable<V> { V call() throws Exception;}<br />Future – result of an asynchronous computationFuture<V> { V get();boolean cancel();booleanisCancelled();booleanisDone();}<br />22<br />3 March 2011<br />
    23. 23. Asynchronous results<br />class QuoteProcessor {<br />ExecutorService exec = ...<br />processQuotes() {<br /> List<QuoteTask> tasks = ...<br /> List<Future<TravelQuote>> futures = <br />exec.invokeAll(tasks);<br /> List<TravelQuote> quotes = new ArrayList<>();<br /> for(Future<TravelQuote> f : futures)<br />quotes.add(f.get());<br /> return quotes;<br /> }<br />}<br />23<br />3 March 2011<br />
    24. 24. Scheduled Processing<br />Use ScheduledThreadPoolExecutor instead of java.util.Timer<br />executor = new ScheduledThreadPoolExecutor();<br />executor.scheduleWithFixedDelay(new BatchProcess(), 10, 10, unit);<br />// executor.scheduleWithFixedRate(...)<br />// other threads are adding to this queue:<br />queue = new LinkedBlockingDeque();<br />class BatchProcess implements Runnable {<br /> public void run() {<br /> List data = new ArrayList ();<br />queue.drainTo(data);<br /> // process data list in a batch<br /> }<br />}<br />24<br />3 March 2011<br />
    25. 25. ThreadPoolExecutor<br />ThreadPoolExecutor configurations<br />Core and maximum pool <br />On-demand construction<br />Creating new threads<br />Keep-alive times<br />Queue<br />Rejected tasks<br />Hook methods<br />Queue maintenance<br />Finalization<br />25<br />3 March 2011<br />
    26. 26. More concurrent APIs<br />Locks<br />Condition<br />Lock<br />ReadWriteLock<br />ReentrantLock<br />Atomic<br />Boolean, long<br />Miscellaneous<br />Semaphore, Barriers<br />26<br />3 March 2011<br />
    27. 27. Fork Join (coming in JDK 7)<br />The fork/join framework is designed to make divide-and-conquer algorithms easy to parallelize.<br />For example, recursive algorithms where the control path branches out over a few paths and they each process a part of the data set.  <br />The typical setup is a new class is created that extends either the RecursiveActionor RecursiveTaskclass.   <br />27<br />3 March 2011<br />
    28. 28. Fork Join Example<br />class ForkJoinMain {<br /> main() {<br />ForkJoinPool pool = new ForkJoinPool();<br />int[] data = [data set];<br /> long sum = pool.invoke(<br /> new SumTask(data, 0, data.length - 1));<br /> long sumSquares = pool.invoke(<br /> new SumSquaresTask(data, 0, data.length - 1));<br /> long max = pool.invoke(<br /> new MaxTask(data, 0, data.length - 1));<br /> }<br />}<br />28<br />3 March 2011<br />
    29. 29. Fork Join Example<br />abstract class AbstractExampleTask extends RecursiveTask<Long> {<br />AbstractExampleTask(int[] data, intfirstIndex, <br />intlastIndex) { ... }<br /> Long compute() {<br /> if (getLength() < THRESHOLD) {<br /> return directlySolve();<br /> }<br />AbstractExampleTask left = getSubtask(first, half()-1);<br />AbstractExampleTask right = getSubtask(half(), last);<br />left.fork();<br />right.fork();<br /> return handleResults(left.join(), right.join());<br /> }<br />}<br />29<br />3 March 2011<br />
    30. 30. class SumSquaresTask extends AbstractExampleTask {<br />SumSquaresTask(...) { ... }<br /> Long directlySolve() {<br /> long accum = 0L;<br /> for (int i = 0; i < getLength(); i++) {<br />accum = accum + (get(i) * get(i));<br /> }<br /> return accum;<br /> }<br /> Long handleResults(Long leftLong, Long rightLong) {<br /> return leftLong + rightLong;<br /> }<br />AbstractExampleTaskgetSubtask(int start, int end) {<br /> return new SumSquaresTask(data, start, end);<br /> }<br />}<br />30<br />3 March 2011<br />Fork Join Example<br />
    31. 31. Summary<br />Recommended order of use<br />Use high level java.util.concurrent APIs<br />Low level locking with synchronization<br />Volatile variables and java.util.concurrent.atomic classes<br />Prefer correctness over speed<br />31<br />3 March 2011<br />
    32. 32. Q&A<br />32<br />3 March 2011<br />

    ×