Fork/Join for Fun and Profit!




               @Sander_Mak
What is the problem anyway?
What is the problem anyway?
What is the problem anyway?
What is the problem anyway?
‣ So let the Compiler figure out the hard stuff!
          if (n < 2) n else fib(n - 1) + fib(n - 2)



                          n < 2




                 n




‣ Or maybe not ...
Fork/Join in pictures

Fork:
Recursively decompose
                                              Result
large task into subtasks
                                              Task 1

Join:                           Task 2                 Task 3
Await results of
recursive tasks            Task 4    Task 5       Task 6    Task 7

and combine
Fork/Join in pseudocode


compute(problem) {
  if (problem.size < threshold)
    directlySolve(problem)
  else {
    do-forked {
       leftResult = compute(left(problem))
       rightResult = compute(right(problem))
    }
    join(leftResult, rightResult)
    return combine(leftResult, rightResult)
  }
}
ForkJoinPool


Introducing:
  java.uCl.concurrent.ForkJoinPool
                                               ForkJoinTask
  java.uCl.concurrent.ForkJoinTask


                                     RecursiveAction   RecursiveTask
ForkJoinPool:
void            execute (ForkJoinTask<?>)
T               invoke (ForkJoinTask<T>)
ForkJoinTask<T> submit (ForkJoinTask<T>)
  
ForkJoinPool


Introducing:
  java.uCl.concurrent.ForkJoinPool   Worker 1



‣    Implements ExecutorService
‣    Autosizing workers              Worker 2
‣    Double‐ended queue
‣    Workstealing algorithm
                                     Worker 3
  
Sorting demo



Mergesort
ForkJoinTasks

‣ 100 < ‘basic computaConal steps’ < 10.000
‣ Acyclic, typically decreasing in size
‣ Join doesn’t block thread!
‣ Do: 
    ‣ OpCmize sequenCal threshold
    ‣ Share, don’t copy input (task locality)
‣ Don’t:
    ‣ Synchronize/lock (but use: Phaser)
    ‣ Do blocking I/O
Work stealing




Worker 1         Worker 2   Worker 3


           ForkJoinPool
Speedups
What about threads?


‣ Heavyweight (try starCng a million)
‣ Implicit dependencies between tasks
   ‣ Manual synchronizaCon
   ‣ Deadlock/livelock/race condiCons
‣ Hard to scale to available parallelism
Pooling/ExecutorService then?


‣ ForkJoinPool implements ExecutorService
‣ Coarse‐grained independent tasks
‣ Recursively decomposed tasks spend most Cme 
  waiCng
   ‣ In normal threadpool: starvaCon
‣ Task‐queue of threadpool‐backed ExecutorService not 
  opCmized for many small tasks
‣ No workstealing
Map/Reduce?




Environment    Single JVM          Cluster

Model          Recursive forking   O^en single map

Scales with    Cores/CPUs          Nodes

Worker         Workstealing        No inter‐node 
interacDon                         communicaCon
Demo


Sony’s been hacked...




            Are we compromised...?
Fork/Join and


‣ ForkJoinPool starts threads
  ‣ Illegal in EJBs
  ‣ Fair game in servlets/CDI beans
‣ Don’t create ForkJoinPool for each request
‣ Idea: WorkManager to create poolthreads
‣ Single pool, async submit(ForkJoinTask)
  ‣ Don’t Ce up request thread: Servlet 3.0
Alternatives outside Java?


‣   Actors
‣   So^ware transacConal memory
‣   Dataflow concurrency
‣   Agents
‣   ... Some of this built on F/J



            Akka                    GPars
Criticism


‣ ImplementaCon too complex (uses Unsafe)
‣ Some assumpCons quesConable
   ‣ 1‐1 mapping workerthread/OS thread
   ‣ Workstealing best opCon?
‣ Scalability 100+ cores?
Future
                                                               GPU?
                                                 Java 8        OpenCL?

                                     Java 7
                                                 Parallel
                 Java 5                          Collections
                                     Fork/Join
Java
1.0 - 1.4        - j.u.concurrent:
                 high-level locks,
                 concurrent coll.
- threads
- synchronized
- volatile
Future




int scanLog(List<String> lines, String query) {
   Pattern p = ...
   return lines.parallel()
               .filter(s => p.matcher(s).matches())
               .count();

}
ForkJoinPool.shutDownNow()


       Questions?




Code @ bit.ly/jfall-forkjoin