java 8 - a step closer to parallelism

27
Java 8 A step closer to Parallelism

Upload: jbugkorea

Post on 11-May-2015

699 views

Category:

Technology


1 download

Tags:

DESCRIPTION

JBUG 2013 10th Anniversary Conference

TRANSCRIPT

Page 1: Java 8 - A step closer to Parallelism

Java 8

A step closer to Parallelism ����������� ������������������  

Page 2: Java 8 - A step closer to Parallelism
Page 3: Java 8 - A step closer to Parallelism
Page 4: Java 8 - A step closer to Parallelism

JDK General Evolution Policy����������� ������������������  

!  Don't break binary compatibility !  Avoid introducing source incompatibilities. !  Manage behavioral compatibility change

Extends to Language Evolution ����������� ������������������  

!  Continue to recognize old class files !  Limit cases where current legal code stops compiling !  Avoid changes in code generation introducing behavioral changes

Page 5: Java 8 - A step closer to Parallelism

Modernizing the Java Platform in JDK8����������� ������������������  

!  Language –  Lambda Expressions (Closures) –  Interface Evolution (default methods)

!  Libraries –  Bulk data operations on Collections –  More library support for Parallelism

!  JVM –  Default Methods –  Enhancement to invokedynamic

Page 6: Java 8 - A step closer to Parallelism

What is a Lambda Expression?����������� ������������������  

!  A Lambda expression is an anonymous method. –  Has an argument list, a return type and a body.

!  (Object o) -> o.toString()

–  Can refer to values from the enclosing lexical scope. !  (Person p) -> p.getName().equals(name)

!  A method reference is a reference to an existing method. –  Object :: toString

!  Allow you to treat code as data. –  Behavior can be stored in variables and passed to methods. ����������� ������������������  

Page 7: Java 8 - A step closer to Parallelism

External Iteration����������� ������������������  !  Lets say I write a code to check marathon method. !  Check each marathon. If it can’t be finished on time, return the marathon that

can be a problem, otherwise return null.

private Marathon checkMarathons(List<Marathon> problemMarathons) { Marathon problemMarathon = null; Iterator<Marathon> marathonItr = problemMarathons.iterator(); while (marathonItr.hasNext() && problemMarathon == null) { Marathon marathon = marathonItr.next(); problemMarathon = chckMarathon(marathon); } return problemMarathon;

} –  Loop is inherently sequential. –  Client has to manage iteration and parallelization if needed. –  bring the data to the code ����������� ������������������  

Page 8: Java 8 - A step closer to Parallelism

Internal Iteration with Lambda����������� ������������������  

!  We could write this as

private Optional<Marathon> checkMarathons(List<Marathon> problemMarathons) { return problemMarathons.stream(). map(p->checkMarathon(p)). filter(p-> p!=null). findfirst();

} –  bring the operation to the data –  Library free to use parallelism(like fork/join), out-of-order execution, laziness. –  Client passes behavior into APIs as data –  Enables APIs designers to build more powerful, expressive APIs.

!  And easily make it execute in parallel !!!����������� ������������������  

Page 9: Java 8 - A step closer to Parallelism

Interface Evolution����������� ������������������  

!  Interfaces are a double-edged sword –  Cannot compatibly evolve them unless you control all implementations –  Reality : APIs age –  What to do with old APIs :

! Let the APIs stagnate ! Replace it in entirely ! Modify existing APIs

!  Burden of API evolution should fall to implementors, not users.

Page 10: Java 8 - A step closer to Parallelism

Functional Interfaces����������� ������������������  

!  We have used single-method interfaces to represent functions –  Runnable, Comparator, ActionListener

!  Lets call them Functional Interfaces. !  And introduce some new ones like Predicate<T>, Block<T> !  A lambda expression evaluates to an instance of a functional inte

rface. –  Predicate<String> isEmpty = s->s.isEmpty(); –  Predicate<String> isEmpty = String::isEmpty; –  Runnable r = ()->{System.out.println(“lambda”);}

Page 11: Java 8 - A step closer to Parallelism

Taking values to higher order����������� ������������������  

!  Instead of supplying values to specific library methods like here

public interface Collection<E> { boolean remove(Object o); }

!  We’re going to supply behavior to general library methods. public interface Collection<E> { boolean removeIf(Predicate<? Super E> p); }

!  Each stage has specific operation !  Client code reads like problem statement

Predicate is an interface with a single abstract boolean-valued method test. removeIf() executes test for each element and if test() returns true, removeIf() removes that element.

Page 12: Java 8 - A step closer to Parallelism

Default Methods����������� ������������������  

!  A default method provides an implementation in the interface.

!  Woven in by the VM at link time.

!  Multiple Inheritance? –  Java always had multiple inheritance of TYPES –  This adds multiple inheritance of BEHAVIOR interface Collection<T> {

... default void forEach(Block<T> action) { for (T t : this) action.apply(t); }

}

Page 13: Java 8 - A step closer to Parallelism

Default Methods – Inheritance Rules����������� ������������������  

!  Rule 1 – prefer superclass methods to interface methods ("Class wins")

!  Rule 2 – prefer more specific interfaces to less ("Subtype wins")

!  Rule 3 – otherwise, act as if the method is abstract. In the case of conflicting defaults, the concrete class must provide an implementation.

Page 14: Java 8 - A step closer to Parallelism

Pipes and Filters����������� ������������������  

!  Venerable unix tool-building pattern ps –ef | grep login | cut –c 50- | head

!  And in Enterprise integration patterns Incoming Order -> Pipe|Filter -> Decrypt -> Pipe|Filter -> Authenticate

-> Pipe|Filter -> De-Dup -> Pipe -> Order

!  Pipes and Filters in Collections ����������� ������������������  problemMarathons.stream() .map(p->checkMarathon(p)) .filter(p->p!=null) .findFirst();

����������� ������������������  

����������� ������������������  

Page 15: Java 8 - A step closer to Parallelism

Bulk Operations on Collections����������� ������������������  Bulk operations on collections also enable a map / reduce style of programming. For example, the above code could be further decomposed by getting a stream from the shapes collection, filtering the red elements, and then iterating only over the filtered elements. shapes.stream()

.filter(s -> s.getColor() == RED) .forEach(s -> { s.setColor(BLUE); });

!  Compose compound operations from basic building blocks. !  Each stage has specific operation !  Client code reads like problem statement

Page 16: Java 8 - A step closer to Parallelism

Streams & Fork/Join Parallelism����������� ������������������  Streams !  Represents streams of values, not a data structure. !  Source can be collection, array, functions, I/O…

collection.stream() .filter(f->f.isBlue()) .map(f->f.getBar()) .forEach(System.out…);

Fork/Join Parallelism !  Powerful and efficient but not so easy !  Divide problem into subsets, solve in parallel and combine results.

Page 17: Java 8 - A step closer to Parallelism

Stream Parallelization����������� ������������������  

!  Collection.parallel().filter(…).map(…).reduce(…);

!  ConcurrentHashMap.parallel(ForkJoinPool) –  Returns parallel view of CHM –  Methods : forEach, forEachEntry, forEachKey, forEachValue –  Consider forEachValue(ConcurrentHashMap.Action<V> action)

! Creates a new ForEachValueTask ! Subclass of ForkJoinTask ! Submits that to the ForkJoinPool ! ForkJoinPool executes ForEachValueTask on one of its threads.

Page 18: Java 8 - A step closer to Parallelism
Page 19: Java 8 - A step closer to Parallelism

Stream Parallelization����������� ������������������  

! ConcurrentHashMap.ForEachValueTask

@SupressWarnings(“unchecked”) public final void compute() { final Action<V> action = this.action; if (action == null) throw new Error(NullFunctionMessage); int b = batch(), c; while (b> 1 && baseIndex != baseLimit) { do{} while (@casPending(c=pending, c+1)); new ForEachValueTask<K,V>(this, b>>>=1, true, action).fork(); Object v; while ((v == advance()) != null) action.apply((V)v); tryComplete(); }

}

Page 20: Java 8 - A step closer to Parallelism

More fine-grained APIs����������� ������������������  !  Sorting a list using comparator

Collections.sort(planList, new Comparator<Plan>() { public int compare(Plan P1, Plan P2) { return P1.getTask().compareTo(P2.getTask()); } }

The method compare must extract the first level sort keys and then compare them.

!  Suppose we have a method that accepts and returns behaviors :

Comparator<T> comparing(Mapper<T,U> m); Now, its much easier to create custom comparators :

Comparator<Plan> byTask = Comparators.compare(p->getTask)); Comparator<Plan> byDuration = Comparators.compare(p->getDuration));

Page 21: Java 8 - A step closer to Parallelism

Composing fine-grained Methods����������� ������������������  

!  Methods and Comparators can now be composed –  new Comparator method

Collections.sort(planList, byTask.compose(byDuration)); And also

planList.sort(byTask.compose(byDuration));

Page 22: Java 8 - A step closer to Parallelism

How is lambda created?����������� ������������������  

!  Using an anonymous inner class??

problemMarathon.removeIf(new Predicate<Marathon>() { public boolean test(Marathon p) { return p.equals(problemMarathon) }

});

!  Let the static compiler emit a declarative recipe for creating a lambda.

!  Let the runtime execute that recipe however it deems best

!  This is like a job for invokedynamic??����������� ������������������  ����������� ������������������  ����������� ������������������  

Page 23: Java 8 - A step closer to Parallelism

Bytecode Invocation Methods����������� ������������������  

!  The JVM has 4 bytecodes for method invocation : –  invokestatic for static methods. –  invokevirtual for class methods –  invokeinterface interface methods –  invokespecial for constructors, private methods and super calls.

!  New Bytecode Tool – invokedynamic –  The JVM adds a fifth invocation mode: invokedynamic (indy) –  Behavior of invoke(virtual, static, interface) are fixed.

Page 24: Java 8 - A step closer to Parallelism

New Bytecode Tool - invokedynamic����������� ������������������  

!  Any indy call site has three group of operands : –  A bootstrap method –  A static argument list –  A dynamic argument list

!  We use indy to embed a recipe for constructing a lambda at the capture site. –  Desugared implementation method. –  Functional interface we are converting to. –  Values captured from lexical scope.

!  The captured site is called lambda factory. –  Invoked with indy, returns an instance of functional interface

Page 25: Java 8 - A step closer to Parallelism

Desugaring lambdas to methods����������� ������������������  

!  First we desugar the lambda to a method –  Signature matches functional interface method. –  Captured arguments prepended if any –  Simplest lambdas desugar to static methods.

Predicate<Person> olderThanK = p->p.getAge() >= k; private static boolean lambda$1(int capturedK, person p) {

return p.getAge() >= capturedK; } ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  ����������� ������������������  

Page 26: Java 8 - A step closer to Parallelism

Factories and Metafactories����������� ������������������  

!  We generate an indy call site, which returns the lambda. –  This is the lambda factory.

–  Bootstrap for the lambda factory selects the translation strategy. Bootstrap

is called the lambda metafactory.

list.removeAll(p->p.getAge() >= minAge); Predicate $p = indy[bootstrap=LambdaMetafactory, staticargs=[Predicate, lambda$1], dynargs=[minAge]]; list.removeAll($p); Private static boolean lambda$1(int capturedK, Person p) { return p.getAge() >= capturedK;

} –  Captured arguments passed to lambda factory. ����������� ������������������  

Page 27: Java 8 - A step closer to Parallelism

27����������� ������������������  

Sati ([email protected])

http://www.jboss.org

https://www.facebook.com/groups/jbossusergroup