Java 10 New Features With Example

Description of image
This is the featured image.

1. Local Variable Type Inference: Java 10 introduced the "var" keyword, which allows for type inference of local variables. This means that the type of a variable can be inferred from the context in which it is used, rather than being explicitly defined. For example:

1var myList = new ArrayList<String>();

The type of myList is inferred to be ArrayList<String> and no longer needs to be explicitly defined.

2. Parallel Full GC for G1: Java 10 included a new garbage collector called G1, which is designed to reduce pause times and improve application responsiveness. G1 uses a parallel, concurrent, and incrementally compacting approach to garbage collection.

A "Parallel Full GC for G1" is a type of garbage collection (GC) that is used in the G1 garbage collector, which is a component of the Java Virtual Machine (JVM). The G1 collector uses a concurrent and parallel approach to GC, and the "Parallel Full GC" is one of the phases that it goes through as it frees up memory.

During a "Parallel Full GC" all the live objects are identified and unmarked, after that all the unmarked objects are swept out of the heap. This process is done concurrently and in parallel by multiple GC threads to make it faster.

Here is an example of the GC log output that shows a Parallel Full GC event:

 1[Full GC (G1 Evacuation Pause) [PSYoungGen: 1024K->0K(2048K)] [ParOldGen: 8192K->8192K(8192K)] [Metaspace: 3347K->3347K(1056768K)]
 2, 0.0187536 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]
 3[GC Worker Start (ms): Min: 4275.7, Avg: 4275.8, Max: 4275.9, Diff: 0.2]
 4[Ext Root Scanning (ms): Min: 0.0, Avg: 0.1, Max: 0.3, Diff: 0.3, Sum: 0.8]
 5[Update RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
 6   [Processed Buffers: Min: 0, Avg: 0.0, Max: 0, Diff: 0, Sum: 0]
 7[Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
 8[Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
 9[Object Copy (ms): Min: 38.5, Avg: 38.5, Max: 38.5, Diff: 0.0, Sum: 308.0]
10[Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
11   [Termination Attempts: Min: 1, Avg: 1.0, Max: 1, Diff: 0, Sum: 8]
12[GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
13[GC Worker Total (ms): Min: 38.6, Avg: 38.6, Max: 38.6, Diff: 0.0, Sum: 308.8]
14[GC Worker End (ms): Min: 4314.4, Avg: 4314.4, Max: 4314.4, Diff: 0.0]

In this example, the GC pause took 0.0187536 seconds, during that time the PSYoungGen (young generation) decreased from 1024K to 0K, the ParOldGen (old generation) remained the same 8192K, and the Metaspace usage remained the same at 3347K. Additionally, GC worker start and end time (ms) is also listed.

The worker threads are used for parallelizing the full GC, for example, the GC worker total time is the total time taken by all the worker threads and the GC worker end time is the end time for all the worker threads.

Also, the GC log shows various GC phases like Ext Root Scanning, Update RS, Scan RS, Code Root Scanning, Object Copy, Termination, GC Worker Other. Each of these phases is done by the worker threads in parallel and the GC log shows the min, avg, max and sum of time taken by each phase. This can help in understanding the GC performance and finding bottlenecks if any.

3. Application Class-Data Sharing: Java 10 introduced the ability to share class data between multiple JVMs. This allows multiple JVMs to share the same class data, reducing the memory footprint of each JVM and improving startup time.

Class-Data Sharing (CDS) is a feature in the Java HotSpot Virtual Machine (JVM) that allows multiple JVMs to share common class metadata. This can help to reduce the memory footprint of a Java application and improve startup time.

An example of using CDS in a Java application is as follows:

  • Create a CDS archive:
1java -Xshare:dump
  • Start the Java application with the CDS archive:
1java -Xshare:on -jar myapp.jar

Here, the option -Xshare:dump is used to create a CDS archive. The archive will be saved in the file ./classes.jsa. The option -Xshare:on is used to enable the use of the CDS archive when starting the Java application, and the -jar option specifies the location of the application's JAR file.

Alternatively, you can also use -XX:ArchiveClassesAtExit=<file> to create the CDS archive when the JVM exits and -XX:SharedArchiveFile=<file> to use the CDS archive when starting the JVM.

It is important to note that not all classes can be shared with CDS, classes that are not eligible for sharing include those that are loaded by the bootstrap class loader, classes loaded dynamically at runtime, and classes loaded from the classpath with the -Xbootclasspath or -Xpatch options.

4. Thread-Local Handshakes: Java 10 added a new mechanism for performing thread-local handshakes, which allows for more fine-grained control over the execution of threads. This can be used for tasks such as stack scanning, thread-local storage reclamation, and safepoint polling.

A Thread-Local Handshake (TLH) is a feature in the Java Virtual Machine (JVM) that allows the JVM to pause individual threads, rather than all threads, for certain operations. This can be useful in situations where only a subset of threads need to be paused, such as during a garbage collection (GC) event.

Here's an example of how Thread-Local Handshakes can be used in Java:

 1// Thread-local variable that stores a counter
 2ThreadLocal<Integer> counter = new ThreadLocal<Integer>() {
 3    @Override
 4    protected Integer initialValue() {
 5        return 0;
 6    }
 9// Thread-local variable that stores a boolean flag
10ThreadLocal<Boolean> flag = new ThreadLocal<Boolean>() {
11    @Override
12    protected Boolean initialValue() {
13        return false;
14    }
17// Thread that increments the counter and sets the flag
18Thread t1 = new Thread(() -> {
19    while (true) {
20        counter.set(counter.get() + 1);
21        flag.set(true);
22    }
25// Thread that checks the flag and prints the counter
26Thread t2 = new Thread(() -> {
27    while (true) {
28        if (flag.get()) {
29            System.out.println("Counter: " + counter.get());
30            flag.set(false);
31        }
32    }
35// Start the threads

In this example, we have two threads t1 and t2. The first thread increments a thread-local counter and sets a thread-local flag to true. The second thread checks the flag and if it's true, it prints the counter and sets the flag to false.

In this way, we can use Thread-Local Handshakes to pause only the threads that need to be paused, rather than all threads, thus reducing the overhead of pausing all threads.

Additionally, Thread-local handshakes can also be used to implement safe points which are used by the JVM during a GC event, this allows the GC to only pause a specific thread if it holds a certain object or has certain properties, rather than pausing all threads.

5. Heap Allocation on Alternative Memory Devices: Java 10 added support for allocating the Java heap on alternative memory devices, such as NV-DIMM memory. This allows for increased memory capacity and improved performance in certain use cases.

Java Heap Allocation on Alternative Memory Devices is a feature that allows Java applications to allocate memory on non-volatile memory devices, such as Solid State Drives (SSD) or Persistent Memory (PMEM). This can provide significant performance improvements, particularly for large data sets and memory-intensive applications.

Here's an example of how this feature can be used in Java:

 1// Allocate a memory-mapped file on an SSD
 2Path path = Paths.get("/path/to/ssd/file.dat");
 3FileChannel channel =, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE);
 4MappedByteBuffer buffer =, 0, 100_000_000);
 6// Create a direct ByteBuffer that uses the memory-mapped file on the SSD
 7ByteBuffer directBuffer = buffer.asReadWriteBuffer();
 9// Allocate a byte array on the direct buffer
10byte[] data = new byte[1000000];

In this example, we are creating a memory-mapped file on an SSD and creating a direct ByteBuffer that uses the memory-mapped file. The byte array is then allocated on the direct buffer, which is backed by the memory-mapped file on the SSD.

This allows the application to access the data stored on the SSD with the same memory management that it would use for data stored in regular heap memory.

Additionally, With JDK 14 and above, the Java Memory Model (JMM) has been enhanced to support the allocation of objects in off-heap memory, this allows to use the DirectByteBuffer objects allocated on alternative memory devices as regular heap objects, this is done using the sun.misc.Unsafe class, and it's only recommended to be used by experts who are familiar with the JMM implications.

6. Root Certificates: Java 10 included a new root certificate store that contains a set of root CA certificates. This allows for improved security and better control over the trust of SSL/TLS certificates. Java 10 introduced a new feature called "Root Certificates" which allows the JDK to automatically trust certain root certificates, without requiring them to be manually installed in the truststore.

Here's an example of how this feature can be used in Java:

 1// Create a URL object for a secure website
 2URL url = new URL("");
 4// Open a connection to the website
 5HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
 7// Set the connection to use the default SSL socket factory
10// Connect to the website
13// Check if the connection is trusted
14if (connection.getPeerPrincipal() != null) {
15    System.out.println("Connection is trusted.");
16} else {
17    System.out.println("Connection is not trusted.");

In this example, we are connecting to a secure website using the HttpsURLConnection class and setting the connection to use the default SSL socket factory. The getPeerPrincipal() method is then used to check if the connection is trusted. If the method returns a non-null value, it means that the connection is trusted, and if it returns a null value, it means that the connection is not trusted.

This feature allows to use the default list of root CA's trusted by the JDK, and it also allows to use the system's root CA's if they are present, This feature can be useful in cases where it is not feasible to manually install root certificates in the truststore, or in the case of using a JDK that has a reduced truststore.

It's worth mentioning that, This feature does not provide additional security, it just reduces the administrative effort of maintaining the truststore.

7. Experimental Java-Based JIT Compiler: Java 10 introduced an experimental feature called "Java-Based JIT Compiler", which allows the Java Virtual Machine (JVM) to use Java code to perform just-in-time (JIT) compilation, instead of using the traditional C++-based JIT compiler. This can provide several benefits, such as improved performance and better maintainability.

Here's an example of how this feature can be used in Java:

1// Enable the Java-based JIT compiler
2-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler

This flag allows to enable the experimental Java-based JIT compiler, the JIT compiler is a component that converts the bytecode of a Java method into native machine code at runtime, this happens when the JVM detects that a method is called frequently, this allows the JVM to execute the method faster, but also it increases the startup time of the JVM.

It's worth mentioning that this feature is experimental and it's not recommended to be used in production environments, it's recommended to use it in controlled test environments to get the performance benefits.

Additionally, the Java-based JIT compiler is not the default JIT compiler that ships with the JDK, it's an experimental feature and it's not guaranteed that it will be included in future versions of the JDK.

These are just a few of the new features in Java 10. Overall, this release focused on performance improvements and small enhancements to the language, rather than introducing major new features.

Posts in this Series

comments powered by Disqus