Date post: | 11-May-2015 |
Category: |
Technology |
Upload: | jbugkorea |
View: | 697 times |
Download: | 1 times |
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
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
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. ����������� ������������������
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 ����������� ������������������
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 !!!����������� ������������������
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.
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”);}
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.
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); }
}
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.
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();
����������� ������������������
����������� ������������������
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
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.
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.
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(); }
}
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));
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));
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??����������� ������������������ ����������� ������������������ ����������� ������������������
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.
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
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; } ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������
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. ����������� ������������������
27����������� ������������������
Sati ([email protected])
http://www.jboss.org
https://www.facebook.com/groups/jbossusergroup