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

Flavors of Concurrency in Java [JavaZone`15]

5d01eb7205b787b5991db85a11ee5e68?s=47 Oleg Šelajev
September 10, 2015

Flavors of Concurrency in Java [JavaZone`15]

Software has evolved so much that singlethreaded programs are rarely enough now. In this talks we'll cover several approaches to organising your concurrent Java code: from managing threads to actor frameworks, to software transactional memory.
Writing concurrent code that is also correct is unbelievably hard. Naturally, humanity has developed a number of approaches to handle concurrency in the code, starting from basic threads that follow the hardware way to do concurrency to higher level primitives like fibers and work-stealing solutions. But which approach is the best for you?

In this session, we'll take a look at a simple concurrent problem and solve it using different ways to manage concurrency: threads, executors, actors, fibers, monadic code with completable futures. All these approaches are different from the simplicity, readability, configuration and management point of view.

Some scenarios are better modelled with threads, while sometimes you're better off with actors. We'll discuss the benefits of each approach and figure out when it's worth pursuing in your project.

5d01eb7205b787b5991db85a11ee5e68?s=128

Oleg Šelajev

September 10, 2015
Tweet

Transcript

  1. Oleg Šelajev @shelajev ZeroTurnaround Flavors of Concurrency in Java

  2. whoami @shelajev

  3. None
  4. WHY DO WE CARE?

  5. DEVS CHOOSING TECHNOLOGY

  6. CONCURRENCY | PARALLELISM http://joearms.github.io/2013/04/05/concurrent-and-parallel-programming.html

  7. CONCURRENCY | PARALLELISM https://davidandstan.files.wordpress.com/2015/05/max3.jpg http://pixel.nymag.com/imgs/daily/vulture/2015/05/15/15-mad-max.w529.h352.2x.jpg

  8. CONCURRENCY Shared resources Multiple consumers & producers Out of order

    events Locks & Deadlocks
  9. THEORY

  10. PRACTICE

  11. THREADS ORGANIZED THREADS FORK-JOIN FRAMEWORK COMPLETABLE FUTURES ACTORS FIBERS SOFTWARE

    TRANSACTIONAL MEMORY
  12. HOW TO MANAGE CONCURRENCY? http://zeroturnaround.com/rebellabs/flavors-of-concurrency-in-java-threads-executors-forkjoin-and-actors/

  13. PROBLEM ORIENTED PROGRAMMING

  14. PROBLEM private static String getFirstResult(String question, List<String> engines) { //

    HERE BE DRAGONS, PARALLEL DRAGONS return null; }
  15. None
  16. WHY THREADS Model Hardware Processes Threads

  17. THREADS private static String getFirstResult(String question, List<String> engines) { AtomicReference<String>

    result = new AtomicReference<>(); for(String base: engines) { String url = base + question; new Thread(() -> { result.compareAndSet(null, WS.url(url).get()); }).start(); } while(result.get() == null); // wait for the result to appear return result.get(); }
  18. THREAD SAFETY A piece of code is thread-safe if it

    only manipulates shared data structures in a manner that guarantees safe execution by multiple threads at the same time. https://en.wikipedia.org/wiki/Thread_safety
  19. COMMUNICATION Objects & Fields Atomics* Queues Database

  20. COMMUNICATION

  21. COMMUNICATION

  22. COMMUNICATION The Java Virtual Machine Specification 17.4. Memory Model

  23. TAKEAWAY: THREADS Threads take resources Require manual management Easy Not

    so simple
  24. None
  25. EXECUTORS public interface Executor { void execute(Runnable command); } public

    interface ExecutorCompletionService<V> { public Future<V> submit(Callable<V> task); public Future<V> take(); }
  26. EXECUTORS private static String getFirstResultExecutors(String question, List<String> engines) { ExecutorCompletionService<String>

    service = new ExecutorCompletionService<String>(Executors.newFixedThreadPool(4)); for(String base: engines) { String url = base + question; service.submit(() -> { return WS.url(url).get(); }); } try { return service.take().get(); } catch(InterruptedException | ExecutionException e) { return null; } }
  27. EXECUTORS private static String getFirstResultExecutors(String question, List<String> engines) { ExecutorCompletionService<String>

    service = new ExecutorCompletionService<String>(Executors.newFixedThreadPool(4)); for(String base: engines) { String url = base + question; service.submit(() -> { return WS.url(url).get(); }); } try { return service.take().get(); } catch(InterruptedException | ExecutionException e) { return null; } }
  28. EXECUTORS private static String getFirstResultExecutors(String question, List<String> engines) { ExecutorCompletionService<String>

    service = new ExecutorCompletionService<String>(Executors.newFixedThreadPool(4)); for(String base: engines) { String url = base + question; service.submit(() -> { return WS.url(url).get(); }); } try { return service.take().get(); } catch(InterruptedException | ExecutionException e) { return null; } }
  29. EXECUTORS private static String getFirstResultExecutors(String question, List<String> engines) { ExecutorCompletionService<String>

    service = new ExecutorCompletionService<String>(Executors.newFixedThreadPool(4)); for(String base: engines) { String url = base + question; service.submit(() -> { return WS.url(url).get(); }); } try { return service.take().get(); } catch(InterruptedException | ExecutionException e) { return null; } }
  30. CONCERNS: EXECUTORS Queue size Overflow strategy Cancellation strategy

  31. TAKEAWAY: EXECUTORS Simple configuration Bounded overhead Pushing complexity deeper

  32. http://i.ytimg.com/vi/6_W_xLWtNa0/maxresdefault.jpg

  33. FORK JOIN FRAMEWORK Recursive tasks General parallel tasks Work stealing

  34. FORK JOIN FRAMEWORK Call from non-fork/join clients Call from within

    fork/join computations Arrange async execution execute(ForkJoinTask) ForkJoinTask.fork() Await and obtain result invoke(ForkJoinTask) ForkJoinTask.invoke() Arrange exec and obtain Future submit(ForkJoinTask) ForkJoinTask.fork()
  35. FORK JOIN POOL private static String getFirstResult(String question, List<String> engines)

    { // get element as soon as it is available Optional<String> result = engines.stream() .parallel().map((base) -> { String url = base + question; return WS.url(url).get(); }).findAny(); return result.get(); }
  36. TAKEAWAY: FORK JOIN POOL Efficient Preconfigured Easy to get right

    Easy to get wrong
  37. None
  38. COMPLETABLE FUTURES private static String getFirstResultCompletableFuture(String question, List<String> engines) {

    CompletableFuture result = CompletableFuture.anyOf(engines.stream().map( (base) -> { return CompletableFuture.supplyAsync(() -> { String url = base + question; return WS.url(url).get(); }); } ).collect(Collectors.toList()).toArray(new CompletableFuture[0])); try { return (String) result.get(); } catch (InterruptedException | ExecutionException e) { return null; } }
  39. COMPLETABLE FUTURES private static String getFirstResultCompletableFuture(String question, List<String> engines) {

    CompletableFuture result = CompletableFuture.anyOf(engines.stream().map( (base) -> { return CompletableFuture.supplyAsync(() -> { String url = base + question; return WS.url(url).get(); }); } ).collect(Collectors.toList()).toArray(new CompletableFuture[0])); try { return (String) result.get(); } catch (InterruptedException | ExecutionException e) { return null; } }
  40. Using types java.util.concurrent.CompletableFuture thenApply(Function / Consumer / etc) thenApplyAsync(Function /

    etc)
  41. None
  42. ACTORS static class Message { String url; Message(String url) {this.url

    = url;} } static class Result { String html; Result(String html) {this.html = html;} }
  43. ACTORS static class UrlFetcher extends UntypedActor { @Override public void

    onReceive(Object message) throws Exception { if (message instanceof Message) { Message work = (Message) message; String result = WS.url(work.url).get(); getSender().tell(new Result(result), getSelf()); } else { unhandled(message); } } }
  44. ACTORS public static interface Squarer { //fire-forget void squareDontCare(int i);

    //non-blocking send-request-reply Future<Integer> square(int i); //blocking send-request-reply Option<Integer> squareNowPlease(int i); //blocking send-request-reply int squareNow(int i); }
  45. TAKEAWAY: ACTORS OOP is about messages Multiplexing like a boss

    Supervision & Fault tolerance
  46. http://static1.squarespace.com/static/50aa813ce4b0726ad3f3fdb0/51e1e393e4b0180cf3bcbb46/51e1e39ae4b0fa94cee721f9/1373758363472/forest-by-marshmallow-laser-feast-the-tree-mag-30.jpg

  47. FIBERS Lightweight threads

  48. None
  49. TAKEAWAY: FIBERS Continuations Progress all over the place Bytecode modification

    Highly scalable
  50. None
  51. TRANSACTIONAL MEMORY

  52. TAKEAWAY: TX MEMORY Optimistic writes Retry / Fail ACID

  53. THREADS ORGANIZED THREADS FORK-JOIN FRAMEWORK COMPLETABLE FUTURES ACTORS FIBERS SOFTWARE

    TRANSACTIONAL MEMORY
  54. CONCLUSION

  55. Seven Concurrency Models in Seven Weeks: When Threads Unravel by

    Paul Butcher https://pragprog.com/book/pb7con/seven-concurrency-models-in-seven-weeks
  56. http://www.amazon.com/The-Multiprocessor-Programming-Revised-Reprint/dp/0123973376 The Art of Multiprocessor Programming by Maurice Herlihy, Nir

    Shavit
  57. http://0t.ee/javazone15

  58. oleg@zeroturnaround.com @shelajev Contact me