Java Core | Concurrency in the Java Language and Platform | Fredrik Ohrstrom
Upcoming SlideShare
Loading in...5
×
 

Java Core | Concurrency in the Java Language and Platform | Fredrik Ohrstrom

on

  • 1,657 views

2011-11-02 | 10:00 AM - 11:00 AM | Victoria...

2011-11-02 | 10:00 AM - 11:00 AM | Victoria
Oracle has initiated a renewal of Java and one of the more important goals is to make it easier to write concurrent software that makes use of all cores in modern hardware. This will require changes both to the language Java as well as its virtual machine. I will describe the latest design that we are working on and demonstrate what can be achieved today using the JRockit JVM and how we can improve concurrency in javac itself.

Statistics

Views

Total Views
1,657
Views on SlideShare
1,624
Embed Views
33

Actions

Likes
1
Downloads
44
Comments
0

1 Embed 33

http://lanyrd.com 33

Accessibility

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Java Core | Concurrency in the Java Language and Platform | Fredrik Ohrstrom Java Core | Concurrency in the Java Language and Platform | Fredrik Ohrstrom Presentation Transcript

  • Concurrency in the Java Language and Platform Fredrik Öhrström Principal Member of Technical Staff JRockit+Hotspot . . . . . .
  • Concurrency in the Java Language and Platform Fredrik Öhrström Principal Member of Technical Staff JRockit+HotspotI have worked on the JRockit JVM for the last 6 six years and on the OpenJDK during the last year. Thus I am bi-jvm-lingual. I am now working in the language team led by the Java Language Architect Brian Goetz.Though I am currently sidetracked to rewrite the build system for OpenJDK. . . . . . .
  • The following is intended to outline our general product direction.It is intended for information purposes only, and may not beincorporated into any contract. It is not a commitment to deliverany material, code, or functionality, and should not be relied uponin making purchasing decisions. The development, release, andtiming of any features or functionality described for Oracle’sproducts remains at the sole discretion of Oracle. . . . . . .
  • In the beginning In 1974, Donald Knuth wrote a paper with the title Structured Programming with goto statements. . . . . . .
  • In the beginning In 1974, Donald Knuth wrote a paper with the title Structured Programming with goto statements. “In the late 1960s we witnessed a ’software crisis,’ which many people thought paradoxical because programming was supposed to be easy.” . . . . . .
  • In the beginning In 1974, Donald Knuth wrote a paper with the title Structured Programming with goto statements. “In the late 1960s we witnessed a ’software crisis,’ which many people thought paradoxical because programming was supposed to be easy.” It then takes him approx 60 pages to discuss the problems with for-loops that were relevant at the time. . . . . . .
  • In the beginning In 1974, Donald Knuth wrote a paper with the title Structured Programming with goto statements. “In the late 1960s we witnessed a ’software crisis,’ which many people thought paradoxical because programming was supposed to be easy.” It then takes him approx 60 pages to discuss the problems with for-loops that were relevant at the time. Today, it is even more complicated! . . . . . .
  • double highestScore = 0.0;for (Student s : students) { if (s.gradYear == 2010) { if (s.score > highestScore) { highestScore = s.score; } }} . . . . . .
  • double highestScore = 0.0;for (Student s : students) { if (s.gradYear == 2010) { if (s.score > highestScore) { highestScore = s.score; } }} Traversal logic is encoded into bytecode. . . . . . .
  • double highestScore = 0.0;for (Student s : students) { if (s.gradYear == 2010) { if (s.score > highestScore) { highestScore = s.score; } }} Traversal logic is encoded into bytecode. Business logic is stateful. . . . . . .
  • double highestScore = 0.0;for (Student s : students) { if (s.gradYear == 2010) { if (s.score > highestScore) { highestScore = s.score; } }} Traversal logic is encoded into bytecode. Business logic is stateful. Existing collections impose external iteration . . . . . .
  • double highestScore = 0.0;for (Student s : students) { if (s.gradYear == 2010) { if (s.score > highestScore) { highestScore = s.score; } }} Traversal logic is encoded into bytecode. Business logic is stateful. Existing collections impose external iteration For complex datasets the iterator becomes unnecessary complex. . . . . . .
  • This might sound like a theoretical exercise, but Oracle is affectedby the lack of concurrency in Javac, right at this very moment. . . . . . .
  • . . . . . .
  • . . . . . .
  • . . . . . .
  • . . . . . .
  • . . . . . .
  • Developers need easy to use parallel libraries One of Java’s strengths has always been its libraries Ideally the library should decide which strategy to use to decompose the problem into parallel parts. Obvious places are the collection classes, add parallel: filter, sort, map/reduce, select, collect, detect, reject . . . . . .
  • Developers need easy to use parallel libraries One of Java’s strengths has always been its libraries Ideally the library should decide which strategy to use to decompose the problem into parallel parts. Obvious places are the collection classes, add parallel: filter, sort, map/reduce, select, collect, detect, reject Why don’t we see more parallel libraries today? . . . . . .
  • Without more language support forparallel idioms, people willinstinctively reach for serial idioms. . . . . . .
  • Internal iteration (functional approach) double highestScore = students.filter(new Predicate<Student>() { public boolean op(Student s) { return s.gradYear == 2010; } }).map(new Extractor<Student,Double>() { public Double extract(Student s) { return s.score; } }).max(); . . . . . .
  • Internal iteration (functional approach) double highestScore = students.filter(new Predicate<Student>() { public boolean op(Student s) { return s.gradYear == 2010; } }).map(new Extractor<Student,Double>() { public Double extract(Student s) { return s.score; } }).max(); Not inherently serial. . . . . . .
  • Internal iteration (functional approach) double highestScore = students.filter(new Predicate<Student>() { public boolean op(Student s) { return s.gradYear == 2010; } }).map(new Extractor<Student,Double>() { public Double extract(Student s) { return s.score; } }).max(); Not inherently serial. Traversal logic completely inside collection. . . . . . .
  • Internal iteration (functional approach) double highestScore = students.filter(new Predicate<Student>() { public boolean op(Student s) { return s.gradYear == 2010; } }).map(new Extractor<Student,Double>() { public Double extract(Student s) { return s.score; } }).max(); Not inherently serial. Traversal logic completely inside collection. Stateless! . . . . . .
  • Internal iteration (functional approach) double highestScore = students.filter(new Predicate<Student>() { public boolean op(Student s) { return s.gradYear == 2010; } }).map(new Extractor<Student,Double>() { public Double extract(Student s) { return s.score; } }).max(); Not inherently serial. Traversal logic completely inside collection. Stateless! Can be done in parallel! . . . . . .
  • The noise, the noise double highestScore = students.filter(new Predicate<Student>() { public boolean op(Student s) { return s.gradYear == 2010; } }).map(new Extractor<Student,Double>() { public Double extract(Student s) { return s.score; } }).max(); Not inherently serial. Traversal logic completely inside collection. Stateless! Can be done in parallel! . . . . . .
  • Lambda Expressions . . . . . .
  • Code as data? double highestScore = students.filter(s -> s.gradYear == 2010) .map(s -> s.score) .max(); . . . . . .
  • Code as data? double highestScore = students.filter(s -> s.gradYear == 2010) .map(s -> s.score) .max(); An -> identifies a lambda expression . . . . . .
  • Code as data? double highestScore = students.filter(s -> s.gradYear == 2010) .map(s -> s.score) .max(); An -> identifies a lambda expression Target type parameters . . . . . .
  • Code as data? double highestScore = students.filter(s -> s.gradYear == 2010) .map(s -> s.score) .max(); An -> identifies a lambda expression Target type parameters More than one parameter (a,b)->c . . . . . .
  • Code as data? double highestScore = students.filter(s -> s.gradYear == 2010) .map(s -> s.score) .max(); An -> identifies a lambda expression Target type parameters More than one parameter (a,b)->c Body may be an expression or {statements} . . . . . .
  • Code as data? double highestScore = students.filter(s -> s.gradYear == 2010) .map(s -> s.score) .max(); Code reads like the problem statement: Find the highest score of the students who graduated in 2010” . . . . . .
  • Code as data? double highestScore = students.filter(s -> s.gradYear == 2010) .map(s -> s.score) .max(); Code reads like the problem statement: Find the highest score of the students who graduated in 2010” Shorter than nested for loops, and potentially faster because the collection implementation determines how to iterate . . . . . .
  • Code as data? double highestScore = students.filter(s -> s.gradYear == 2010) .map(s -> s.score) .max(); Code reads like the problem statement: Find the highest score of the students who graduated in 2010” Shorter than nested for loops, and potentially faster because the collection implementation determines how to iterate filter() method body can exploit representation knowledge . . . . . .
  • Code as data? double highestScore = students.filter(s -> s.gradYear == 2010) .map(s -> s.score) .max(); Code reads like the problem statement: Find the highest score of the students who graduated in 2010” Shorter than nested for loops, and potentially faster because the collection implementation determines how to iterate filter() method body can exploit representation knowledge Opportunities for lazy evaluation in filter() and map() . . . . . .
  • Code as data? double highestScore = students.filter(s -> s.gradYear == 2010) .map(s -> s.score) .max(); Code reads like the problem statement: Find the highest score of the students who graduated in 2010” Shorter than nested for loops, and potentially faster because the collection implementation determines how to iterate filter() method body can exploit representation knowledge Opportunities for lazy evaluation in filter() and map() Opportunities for parallelism . . . . . .
  • Lambda Expressions The name comes from the lambda calculus created by Church (1936) . . . . . .
  • Lambda Expressions The name comes from the lambda calculus created by Church (1936) Later explored by Steele and Sussman (1975-1980) . . . . . .
  • Lambda Expressions The name comes from the lambda calculus created by Church (1936) Later explored by Steele and Sussman (1975-1980) Thus by adding lambda expressions we have moved from 1974 (Knuth’s structured gotos) to 1975 (Scheme and lexical lambdas). . . . . . .
  • Lambda Expressions The name comes from the lambda calculus created by Church (1936) Later explored by Steele and Sussman (1975-1980) Thus by adding lambda expressions we have moved from 1974 (Knuth’s structured gotos) to 1975 (Scheme and lexical lambdas). Yay! . . . . . .
  • Lambda Expressions A lambda expression is a lexically scoped anonymous method. . . . . . .
  • Lambda Expressions A lambda expression is a lexically scoped anonymous method. Lexical scoping: can read variables from the lexical environment, including “this”, unlike inner classes. No shadowing of lexical scope, unlike inner classes. Not a member of any class, unlike inner classes. . . . . . .
  • Why were lambda expressions not added earlier to Java? . . . . . .
  • Why were lambda expressions not added earlier to Java? After all, Steele who wrote the lambda papers in 1975, worked in the Java team for several years! . . . . . .
  • Why were lambda expressions not added earlier to Java? After all, Steele who wrote the lambda papers in 1975, worked in the Java team for several years! The reason was the design decision that every memory allocation should be visible as a “new” in Java source code. . . . . . .
  • Why were lambda expressions not added earlier to Java? After all, Steele who wrote the lambda papers in 1975, worked in the Java team for several years! The reason was the design decision that every memory allocation should be visible as a “new” in Java source code. And the reason for this decision was that the hardware of the time simply was not powerful enough. . . . . . .
  • Why were lambda expressions not added earlier to Java? After all, Steele who wrote the lambda papers in 1975, worked in the Java team for several years! The reason was the design decision that every memory allocation should be visible as a “new” in Java source code. And the reason for this decision was that the hardware of the time simply was not powerful enough. But now we have enough hardware to be able to spend significant cpu power on the optimization problems and GC to make this less of a problem. . . . . . .
  • Typing . . . . . .
  • What is the type of a lambda expression? s -> s.gradYear == 2010 Morally, a function type from Student to boolean But Java does not have function types.... . . . . . .
  • What is the type of a lambda expression? s -> s.gradYear == 2010 How would we write a function type? How would it interact with boxing? How would it interact with generics? How would it describe checked exceptions? Would it be possible to overload based on function type? . . . . . .
  • In Java we use interfaces (and abstract classes) in two differentways: . . . . . .
  • In Java we use interfaces (and abstract classes) in two differentways: To specify behaviour: PrintWriter.println(), Student.setGrade(), GraphicsObject.render(). . . . . . .
  • In Java we use interfaces (and abstract classes) in two differentways: To specify behaviour: PrintWriter.println(), Student.setGrade(), GraphicsObject.render(). To specify calling parameters and return value: Runnable.run(), Callable.call(), Comparator.compare(), ActionListener.actionPerformed(),TimerTask.run() . . . . . .
  • In Java we use interfaces (and abstract classes) in two differentways: To specify behaviour: PrintWriter.println(), Student.setGrade(), GraphicsObject.render(). To specify calling parameters and return value: Runnable.run(), Callable.call(), Comparator.compare(), ActionListener.actionPerformed(),TimerTask.run()We can reuse the second kind of interfaces as function types. Forbackwards compatibility. When we have reified Java, then we canmore easily add real function types. . . . . . .
  • Introducing SAM-types A SAM-type is an interface or abstract class with a Single Abstract Method interface Runnable { void run(); } interface Callable<T> { T call(); } interface Comparator<T> { boolean compare(T x, T y); } interface ActionListener { void actionPerformed(...); abstract class TimerTask { ... abstract void run(); ... } . . . . . .
  • The type of a lambda expression is a SAM-type “SAM-conversion” infers a SAM-type for a lambda expression: Predicate<Student> p = s -> s.gradYear == 2010; Invoking the SAM-type’s method invokes the lambdas’s body boolean ok = p.isTrue(aStudent); Instant compatibility with existing libraries! executor.submit( ()->{ println(“Boo”); }); . . . . . .
  • The type of a lambda expression is a SAM-type “SAM-conversion” infers a SAM-type for a lambda expression: Predicate<Student> p = s -> s.gradYear == 2010; Invoking the SAM-type’s method invokes the lambdas’s body boolean ok = p.isTrue(aStudent); Instant compatibility with existing libraries! executor.submit( ()->{ println(“Boo”); }); Lambda expressions may only appear in contexts where they can undergo SAM conversion (assignment, method call/return, cast). . . . . . .
  • double highestScore = students.filter( (Student s)-> s.gradYear == 2010) .map((Student s)-> s.score) .max();Since SAM-conversion uses target typing, the parameter types canbe left out! . . . . . .
  • double highestScore = students.filter( (Student s)-> s.gradYear == 2010) .map((Student s)-> s.score) .max();Since SAM-conversion uses target typing, the parameter types canbe left out! double highestScore = students.filter(s -> s.gradYear == 2010) .map(s -> s.score) .max(); . . . . . .
  • So, lambda expressions are just a better syntax for inneranonymous classes? I.e. more sugar? . . . . . .
  • So, lambda expressions are just a better syntax for inneranonymous classes? I.e. more sugar?No! They cannot be! . . . . . .
  • So, lambda expressions are just a better syntax for inneranonymous classes? I.e. more sugar?No! They cannot be!To understand why, we need to understand how the JVM achieveshigh performance today. . . . . . .
  • static class Coord { final int x, y; Coord(int xx, int yy) { x=xx; y=yy; } Coord add(Coord c) { return new Coord(x+c.x,y+c.y); } double dist(Coord c) { int dx = c.x-x; int dy = c.y-y; return Math.sqrt(dx*dx+dy*dy); }} . . . . . .
  • public static class Matrix { int a,b,c,d; public Matrix(int aa, int bb, int cc, int dd) { a = aa; b = bb; c = cc; d = dd; } public static Matrix scaler(int k) { return new Matrix(k,0,0,k); } public Matrix mul(int k) { return new Matrix(a*k,b*k,c*k,d*k); } Coord mul(Coord co) { return new Coord(co.x*a+co.y*c,co.x*b+co.y*d); }} . . . . . .
  • Calculation [ ] ] [ [ ] [ ] 33 0 k 22 dx ×2× − = 0 33 k 11 dy √ answer = dx2 + dy2 . . . . . .
  • Calculation [ ] ] [ [ ] [ ] 33 0 k 22 dx ×2× − = 0 33 k 11 dy √ answer = dx2 + dy2 public static double test(int k) { return Matrix.scaler(33).mul(2).mul(new Coord(k,k)) .dist(new Coord(22,11)); } . . . . . .
  • Calculation public static void main(String... args) { int i=0; double d = 0; for (;;) { d = test(4711); if (++i > 1000000) { System.out.println("+d); i=0; } } } . . . . . .
  • . . . . . .
  • x86_sub esp ← esp 4x86_mov edi ← eaxx86_test *[0xb722f000] eaxx86_imul eax ← eax 66x86_imul edi ← edi 66x86_mov ecx ← 22x86_sub ecx ← ecx eaxx86_mov esi ← 11x86_sub esi ← esi edix86_imul ecx ← ecx ecxx86_imul esi ← esi esix86_add ecx ← ecx esix86_cvtsi2sd xmm0 ← ecxx86_sqrtsd xmm0 ← xmm0x86_pop ecx esp ← espx86_retxmm0 esp . . . . . .
  • Inlining implies great optimization opportunities . . . . . .
  • But where to inline when using multiple cores? . . . . . .
  • . . . . . .
  • Fortunately a new JVM technology called the MethodHandleis available for us.A MethodHandle is (among many things) a root for inliningthat require no function!A MethodHandle will be hidden behind the SAM-typeinterface.It can express new code using objects on the Java heap. . . . . . .
  • Fortunately a new JVM technology called the MethodHandleis available for us.A MethodHandle is (among many things) a root for inliningthat require no function!A MethodHandle will be hidden behind the SAM-typeinterface.It can express new code using objects on the Java heap.This code can be efficiently optimized. . . . . . .
  • Assume an interface to extract a value from an object:interface Extractor<T, U> { U get(T element); }And a new sort method on Collections using the Extractor:public <T, U extends Comparable<...>>void sortBy(Collection<T> coll, Extractor<T,U> ex) {...}Then, pass a lambda expression that “wraps” a method call:Collections.sortBy(people, p -> p.getLastName() ); SAM conversion types the lambda as Extractor<Person,String> sortBy() can pre-query last names, cache them, build indices... . . . . . .
  • Is that the best we can do? Collections.sortBy(people, p -> p.getLastName() ); Writing little wrapper lambdas will be a pain! Lets reference a method directly! Collections.sortBy(people, Person#getLastName ); Method reference introduced with # (not locked down yet!) No need for () or parameter types in simple cases . . . . . .
  • Another very common use case! To bind user interface callbacks to your code: save_button.addActionListener(this#save); . . . . . .
  • Another very common use case! To bind user interface callbacks to your code: save_button.addActionListener(this#save); Or even shorter: save_button.addActionListener(#save); . . . . . .
  • Recap When code outgrows a lambda expression, write a method and take a method reference Lambda expressions and method references have SAM types Work easily with existing libraries Can specify parameter types explicitly if needed Three kinds of method references (unbound/bound/static) No field references (use method references to getters/setters) . . . . . .
  • Wrap up . . . . . .
  • Collections.sort(people, new Comparator<Person>() { public int compare(Person x, Person y) { return x.getLastName().compareTo(y.getLastName()); }}); . . . . . .
  • Collections.sort(people, new Comparator<Person>() { public int compare(Person x, Person y) { return x.getLastName().compareTo(y.getLastName()); }});Collections.sort(people, (Person x, Person y)-> x.getLastName().compareTo(y.getLastName()) ); . . . . . .
  • Collections.sort(people, new Comparator<Person>() { public int compare(Person x, Person y) { return x.getLastName().compareTo(y.getLastName()); }});Collections.sort(people, (Person x, Person y)-> x.getLastName().compareTo(y.getLastName()) );Collections.sortBy(people, (Person p)-> p.getLastName() ); . . . . . .
  • Collections.sort(people, new Comparator<Person>() { public int compare(Person x, Person y) { return x.getLastName().compareTo(y.getLastName()); }});Collections.sort(people, (Person x, Person y)-> x.getLastName().compareTo(y.getLastName()) );Collections.sortBy(people, (Person p)-> p.getLastName() );Collections.sortBy(people, p -> p.getLastName() ); . . . . . .
  • Collections.sort(people, new Comparator<Person>() { public int compare(Person x, Person y) { return x.getLastName().compareTo(y.getLastName()); }});Collections.sort(people, (Person x, Person y)-> x.getLastName().compareTo(y.getLastName()) );Collections.sortBy(people, (Person p)-> p.getLastName() );Collections.sortBy(people, p -> p.getLastName() );Collections.sortBy(people, Person#getLastName); . . . . . .
  • . . . . . .
  • Lambda expressions . . . . . .
  • Lambda expressions - More concise . . . . . .
  • Lambda expressions - More conciseBetter libraries . . . . . .
  • Lambda expressions - More conciseBetter libraries - More abstract . . . . . .
  • Lambda expressions - More conciseBetter libraries - More abstractType inference . . . . . .
  • Lambda expressions - More conciseBetter libraries - More abstractType inference - Less ceremony . . . . . .
  • Lambda expressions - More conciseBetter libraries - More abstractType inference - Less ceremonyMethod references . . . . . .
  • Lambda expressions - More conciseBetter libraries - More abstractType inference - Less ceremonyMethod references - More reuse . . . . . .
  • Lambda expressions - More conciseBetter libraries - More abstractType inference - Less ceremonyMethod references - More reuseJVM support . . . . . .
  • Lambda expressions - More conciseBetter libraries - More abstractType inference - Less ceremonyMethod references - More reuseJVM support - More performance . . . . . .
  • Thanks! . . . . . .