2. Java 7
Java 6
Jul 2011 Apr 2013 Apr 2015Mar 2014 Sep 2017 Mar 2018 Sep 2018
Java 9
Java 10
Jan 2019
Java 8
Dec 2020
Java 11
Java 8
Java 6
Java 7
Java 8
Java 6
Java 7
For the first time, support spans are known in advanced:
Extended support for Java 7 until July 2022
Extended support for Java 8 until March 2025
Extended support for Java 11 until September 2026
3. What are the biggest challenges when moving past Java 8?
1. Module encapsulation: «Deep Reflection» is no longer allowed.
But: java --illegal-access=permit
Option may be removed in a future version but not yet announced.
2. Gradual removal of accessible, internal API.
Most famously sun.misc.Unsafe
3. Steady removal of deprecated API and modules.
For example Corba.
one time costs
Why should I even update, Java 6 works just fine.
1. Yes, the JVM does have bugs and can segfault (if you do the right things)
2. Performance bugs are more common and can be quite significant.
3. Security exploits are constantly discovered and fixed. Not updating at all is irresponsible.
4. Libraries will eventually update to newer releases and you cannot update these either.
5. public class Foo {
void bar(String value) { /* ... */ }
}
public class Qux {
public static void main(String[] args) throws Exception {
Method bar = Foo.class.getDeclaredMethod("bar", String.class);
// Checked against global setting in security manager
bar.setAccessible(true);
bar.invoke(new Foo(), "value");
}
}
public class Qux {
public static void main(String[] args) {
// Returns a lookup that represents the rights of the calling class
MethodHandles.Lookup lookup = MethodHandles.lookup();
Methodhandle bar = lookup.findVirtual(Foo.class,
"bar",
MethodType.methodType(void.class, String.class));
bar.invokeExact(new Foo(), "value");
}
}
public class Qux {
public static void main(String[] args) throws Exception {
Method bar = Foo.class.getDeclaredMethod("bar", String.class);
bar.invoke(new Foo(), "value");
}
}
1. A reflective call is expensive in its lookup and during a call due to a security check and auto-boxing of arguments.
2. A method handle is expensive in its creation but results in very efficient calls, thanks to polymorphic signatures.
Java reflection and modules
6. package sun.misc;
public class Unsafe {
public native long allocateMemory(long var1);
public native long reallocateMemory(long var1, long var3);
public native void freeMemory(long var1);
public native byte getByte(long var1);
public native void putByte(long var1, byte var3);
public native short getShort(long var1);
public native void putShort(long var1, short var3);
public native char getChar(long var1);
public native void putChar(long var1, char var3);
public native int getInt(long var1);
public native void putInt(long var1, int var3);
public native long getLong(long var1);
public native void putLong(long var1, long var3);
public native float getFloat(long var1);
public native void putFloat(long var1, float var3);
public native double getDouble(long var1);
public native void putDouble(long var1, double var3);
public native long getAddress(long var1);
public native void putAddress(long var1, long var3);
// and more ...
}
7. VarHandle handle = MethodHandles.byteBufferViewVarHandle(
long[].class,
ByteOrder.BIG_ENDIAN);
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
handle.set(buffer, 0, 1L);
long value = (long) handle.get(buffer, 0);
System.out.println(value); // prints 1
Direct memory access without Unsafe
It is also possible to access fields or array elements using a var handle. Doing so, it is also possible to use different
access modes such as volatile, opaque, aquire/release, CAS. Var handles also use polymorphic signatures.
8. package sun.misc;
public class Unsafe {
public native void loadFence();
public native void storeFence();
public native void fullFence();
// and more ...
}
As of today, Java does not expose standard APIs for concurrency primitives but a larger set of access
modes using var hanldes.
9. package sun.misc;
public class Unsafe {
public native Class<?> defineClass(String var1, byte[] var2,
int var3, int var4, ClassLoader var5, ProtectionDomain var6);
public native Class<?> defineAnonymousClass(Class<?> var1, byte[] var2,
Object[] var3);
public native Object allocateInstance(Class<?> var1);
// and more ...
}
10. MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(
AppConfig.class,
MethodHandles.lookup());
byte[] proxyForConfig = ...;
lookup.defineClass(proxyForConfig);
Defining runtime classes without Unsafe
@Configuration
public class AppConfig {
@Bean
/* package-private */ Bar bar() {
return new Bar();
}
@Bean
public Foo foo(Bar bar) {
return new Foo(bar);
}
}
public class AppConfig$Aop extends AppConfig {
AppConfig proxied = ...
@Override
/* package-private */ Bar bar() {
return proxied.bar();
}
@Override
public Foo foo(Bar bar) {
return proxied.foo(bar);
}
}
11. public class AppConfig$Aop extends AppConfig implements ProxyLib {
ProxyLibDispatcher dispacher = ...
@Override
/* package-private */ Bar bar() {
return (Bar) dispatcher.dispatch(
AppConfig.class.getDeclaredMethod("bar"));
}
@Override
public Foo foo(Bar bar) {
return (Foo) dispatcher.dispatch(
AppConfig.class.getDeclaredMethod("bar", Bar.class),
bar);
}
}
How does the proxy actually look like?
Requires the application that defines AppConfig to open its package to the module that creates theproxying library,
not the module that defines the proxy.
12. How does the OpenJDK look like?
OpenJDK lead
OpenJDK member
Contributor
Participant
Group
Project
JEP
http://openjdk.java.net
http://www.oracle.com/technetwork/community/oca-486395.html
http://mail.openjdk.java.net/mailman/listinfo
The future of Java: embrace the group idea and merge features when ready.
No more «show stopper» features. The general problem is that there is
only one release train for:
1. Java virtual machine
2. Java standard library
3. Java programming language
Most people focus on the Java programming language and standard library.
But there is a lot happening in the JVM itself.
13. Project Amber
http://openjdk.java.net/projects/amber/
JEP 286 Local-Variable Type Inference
JEP 301 Enhanced Enums
JEP 302 Lambda Leftovers
JEP 305 Pattern Matching
JEP 323 Local-Variable Syntax for Lambda Parameters
JEP 325 Switch Expressions
JEP 326 Raw String Literals
14. var list = new ArrayList<String>();
Project Amber: local variable type inference
List<String> list = new ArrayList<String>();
var list = (List<String>) new ArrayList<String>();
(foo, bar) -> foo.qux(bar)(Foo foo, Bar bar) -> foo.qux(bar)
(var foo, var bar) -> foo.qux(bar)(@Baz var foo, var bar) -> foo.qux(bar)
var foo;
var bar = null;
var qux = () -> {};
16. Project Amber: switches and pattern matching
String foo;
switch (bar) {
case 1:
foo = "a";
break;
case 2:
foo = "b";
break;
default:
foo = "c";
}
System.out.println(foo);
String foo = switch (bar) {
case 1: break "a";
case 2: break "b";
default: break "c";
}
System.out.println(foo);
String foo = switch (bar) {
case 1 -> "a";
case 2 -> "b";
default -> "c";
}
System.out.println(foo);
String foo = switch (bar) {
case Integer i -> "Number: " + i;
case String s -> s;
default -> "Unknown: " + bar;
}
System.out.println(foo);
17. Project Amber: raw strings
Runtime.getRuntime().exec(""C:Program Filesfoo" bar");Runtime.getRuntime().exec(`"C:Program Filesfoo" bar`);
Runtime.getRuntime().exec(```"C:Program Filesfoo" bar```);
final String sql = "select foo"
+ "from bar"
+ "where qux = baz";
final String sql = `select foo
from bar
where qux = baz`;
final String sqlNoMargin = `select foo
from bar
where qux = baz`.normalize();
@SomeAnnotation(sql)
@SomeAnnotation(sqlNoMargin)
18. Project Loom
http://openjdk.java.net/projects/loom/
Threads are light-weight abstractions within processes that share their process’s resources.
Similarly, fibers (user-level threads) are light-weight abstractions that are executed within a single thread.
Today many servers implement a one-thread-per-request model which does not scale as threads are still fairly
expensive. In Java, any thread is bound to an OS-level thread to better accomendate JNI.
Using callbacks upon blocking operations gives an opportunity to use threads for other operations without
requiring a new thread allocation. Unfortunately, with callback models, control flow gets distributed and call
stacks do no longer represent a causal instruction sequence. Ideally, one could write code in its intended
execution sequence while releasing the thread for a non-CPU-bound statement.
19. void foo() {
int x;
if (Fiber.isResume()) {
x = Fiber.deserialize("foo", "x", STATE_ID);
} else {
x = bar();
}
if (Fiber.isSuspend()) {
Fiber.serialize("foo", x, STATE_ID);
throw new SuspendFiberException();
} else {
qux(x);
}
}
Project Loom
http://openjdk.java.net/projects/loom/
void foo() {
int x = bar();
qux(x);
}
int bar() { ... }
void qux(int val) { ... }
20. suspend fun bar(val: Int): Unit { ... }
fun foo(): Unit {
async {
listOfInts.forEach { bar(it) }
}
}
Project Loom
http://openjdk.java.net/projects/loom/
void foo(int val) throws SuspendExecution { ... }
void bar() {
new Fiber<V>() {
@Override
protected V run() throws SuspendExecution, InterruptedException {
listOfInts.forEach(val -> foo(val)); // ignore checked exception
}
}.start();
}
Kotlin
coroutines
Quasar
fibers
24. Project Valhalla
http://openjdk.java.net/projects/valhalla/
class Point { long x, y; }
void foo() {
Point p1 = new Point(), p2 = new Point();
// ...
}
void bar() {
long p1X = 0, p1Y = 0, p2X = 0, p2Y = 0;
// ...
}
void qux(Point p1, Point p2) { ... }
void baz(long p1X, long p1Y, long p2X, long p2Y) { ... }
25. Project Valhalla
http://openjdk.java.net/projects/valhalla/
void foo() {
Long i1 = 0, i2 = 0;
// ...
}
void bar() {
long i1 = 0, p2 = 0;
// ...
}
value class Point { long x, y; }
Idea: generate a wrapper class for value types automatically instead of explicitly as for the Java built-in primitives.
This makes value types interoperable with existing code, the JVM can box and unbox value types on demand.
Arrays of value types can be allocated in a packed format to optimize cache line-friendly iteration.
Many details to figure out: values do not have an identity and certain methods do not make sense (especially locking).
There are also open questions around serialization, cloning and stack pre-allocation in the Java interpreter.
26. Project Valhalla
http://openjdk.java.net/projects/valhalla/
value class Point { long x, y; }
List<Point> points = new ArrayList<Point>();
List<Long> points = new ArrayList<Long>();
List<long> points = new ArrayList<long>();
class Box<T> { T value; }
class Box { Object value; }
class Box<any T> { T value; }
class Box { Object value; }
class Box{T=long} { long value; }
class Box{T=Point} { Point value; }
runtime
specialization
27. Project Graal
http://openjdk.java.net/projects/graal/
interface JVMCICompiler {
CompilationRequestResult compileMethod(CompilationRequest request);
}
-XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:+UseJVMCICompiler
Graal Compiler: A to-machine code compiler implemented in Java. Can run embedded in the JVM via JVMCI.
Graal VM: A virtual machine that is capable of running and compiling multiple languages using the Graal compiler,
either processing Java byte code or by using a AST toolkit called Truffle that supports languages such as Ruby,
JavaScript, C/C++ or R.
SubstrateVM: A minimal VM that uses the Graal compiler for AOT compilation to create an executable binary.
Since the Graal compiler is itself Java code, the compiler is easier to maintain and safer to use as bugs manifest in
exceptions, not in segmentation faults. The Graal compiler is itself compiled at runtime unless a binary is provided.
This can increase startup times.
28. Project Metropolis
http://openjdk.java.net/projects/metropolis/
HotSpot is implemented in mostly C++. Especially problematic with the C2 compiler which is hard to maintain.
This proposal intends to replace other components in the JVM with Java-implemented components.
The starting point is Graal which offers AOT compilation what would allow the creation of optimized code for
the JVM binaries while the source code can be written in Java.
29. Project Memory Model Update
http://openjdk.java.net/projects/jmm/
package java.lang;
public class String {
private int hash;
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
hash = h = isLatin1()
? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
}
return h;
}
// ...
}
30. Project Memory Model Update
http://openjdk.java.net/projects/jmm/
public class MyVolatileClass {
public volatile String foo;
MyClass(String foo) { this.foo = foo; }
}
public class MyFinalClass {
public final String foo;
MyClass(String foo) { this.foo = foo; }
}
31. Project Shenandoa / project ZGC
http://openjdk.java.net/projects/shenandoa/
http://openjdk.java.net/projects/zgc/
With most GC algorithms, the pauses that are caused by GC is proportional to the total size of the heap.
Shenandoa attempts to offer predictable latency that is independant of a JVM’s heap size.
GCs increasingly transit from stop-the-world to fully-concurrent collection.
Collector Young generation Tenured generation
Serial Stop-the-world Stop-the-world
Parallel Stop-the-world Stop-the-world
CMS Stop-the-world Concurrent mark and sweep
No compaction
G1 Stop-the-world Concurrent mark
Serial compaction
Shenandoah Partially concurrent Concurrent mark and compact
ZGC Partially concurrent Concurrent mark and compact