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

Flavors of Concurrency in Java [JavaZone`15]

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.

Oleg Šelajev

September 10, 2015
Tweet

More Decks by Oleg Šelajev

Other Decks in Programming

Transcript

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

    View Slide

  2. whoami
    @shelajev

    View Slide

  3. View Slide

  4. WHY DO WE CARE?

    View Slide

  5. DEVS CHOOSING TECHNOLOGY

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

  9. THEORY

    View Slide

  10. PRACTICE

    View Slide

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

    View Slide

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

    View Slide

  13. PROBLEM ORIENTED PROGRAMMING

    View Slide

  14. PROBLEM
    private static String
    getFirstResult(String question,
    List engines)
    {
    // HERE BE DRAGONS, PARALLEL DRAGONS
    return null;
    }

    View Slide

  15. View Slide

  16. WHY THREADS
    Model Hardware
    Processes
    Threads

    View Slide

  17. THREADS
    private static String getFirstResult(String question,
    List engines) {
    AtomicReference 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();
    }

    View Slide

  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

    View Slide

  19. COMMUNICATION
    Objects & Fields
    Atomics*
    Queues
    Database

    View Slide

  20. COMMUNICATION

    View Slide

  21. COMMUNICATION

    View Slide

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

    View Slide

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

    View Slide

  24. View Slide

  25. EXECUTORS
    public interface Executor {
    void execute(Runnable command);
    }
    public interface ExecutorCompletionService {
    public Future submit(Callable task);
    public Future take();
    }

    View Slide

  26. EXECUTORS
    private static String getFirstResultExecutors(String question, List
    engines) {
    ExecutorCompletionService service = new
    ExecutorCompletionService(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;
    }
    }

    View Slide

  27. EXECUTORS
    private static String getFirstResultExecutors(String question, List
    engines) {
    ExecutorCompletionService service = new
    ExecutorCompletionService(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;
    }
    }

    View Slide

  28. EXECUTORS
    private static String getFirstResultExecutors(String question, List
    engines) {
    ExecutorCompletionService service = new
    ExecutorCompletionService(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;
    }
    }

    View Slide

  29. EXECUTORS
    private static String getFirstResultExecutors(String question, List
    engines) {
    ExecutorCompletionService service = new
    ExecutorCompletionService(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;
    }
    }

    View Slide

  30. CONCERNS: EXECUTORS
    Queue size
    Overflow strategy
    Cancellation strategy

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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()

    View Slide

  35. FORK JOIN POOL
    private static String getFirstResult(String question,
    List engines) {
    // get element as soon as it is available
    Optional result = engines.stream()
    .parallel().map((base) ->
    {
    String url = base + question;
    return WS.url(url).get();
    }).findAny();
    return result.get();
    }

    View Slide

  36. TAKEAWAY: FORK JOIN POOL
    Efficient
    Preconfigured
    Easy to get right
    Easy to get wrong

    View Slide

  37. View Slide

  38. COMPLETABLE FUTURES
    private static String getFirstResultCompletableFuture(String question, List
    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;
    }
    }

    View Slide

  39. COMPLETABLE FUTURES
    private static String getFirstResultCompletableFuture(String question, List
    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;
    }
    }

    View Slide

  40. Using types
    java.util.concurrent.CompletableFuture
    thenApply(Function / Consumer / etc)
    thenApplyAsync(Function / etc)

    View Slide

  41. View Slide

  42. ACTORS
    static class Message {
    String url;
    Message(String url) {this.url = url;}
    }
    static class Result {
    String html;
    Result(String html) {this.html = html;}
    }

    View Slide

  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);
    }
    }
    }

    View Slide

  44. ACTORS
    public static interface Squarer {
    //fire-forget
    void squareDontCare(int i);
    //non-blocking send-request-reply
    Future square(int i);
    //blocking send-request-reply
    Option squareNowPlease(int i);
    //blocking send-request-reply
    int squareNow(int i);
    }

    View Slide

  45. TAKEAWAY: ACTORS
    OOP is about messages
    Multiplexing like a boss
    Supervision & Fault tolerance

    View Slide

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

    View Slide

  47. FIBERS
    Lightweight threads

    View Slide

  48. View Slide

  49. TAKEAWAY: FIBERS
    Continuations
    Progress all over the place
    Bytecode modification
    Highly scalable

    View Slide

  50. View Slide

  51. TRANSACTIONAL MEMORY

    View Slide

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

    View Slide

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

    View Slide

  54. CONCLUSION

    View Slide

  55. Seven Concurrency
    Models in Seven
    Weeks:
    When Threads Unravel
    by Paul Butcher
    https://pragprog.com/book/pb7con/seven-concurrency-models-in-seven-weeks

    View Slide

  56. http://www.amazon.com/The-Multiprocessor-Programming-Revised-Reprint/dp/0123973376
    The Art of
    Multiprocessor
    Programming
    by Maurice Herlihy, Nir Shavit

    View Slide

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

    View Slide

  58. [email protected]
    @shelajev
    Contact me

    View Slide