JDK 20 Early-Access Release Notes

This is a draft of the release notes that will accompany JDK 20. The contents are subject to change until release.

Build 25

appendToClassPathForInstrumentation must be used in a thread-safe manner (JDK-8296472)


When running an application with a Java agent (e.g. -javaagent:myagent.jar) and a custom system class loader (e.g. -Djava.system.class.loader=MyClassLoader), and the Java agent invokes the Instrumentation.appendToSystemClassLoaderSearch API to append to the class loader search, then the custom system class loader appendToClassPathForInstrumentation method will be invoked to add the JAR file to the custom system class loader's search path.

The JVM no longer synchronizes on the custom class loader while calling appendToClassPathForInstrumentation. The appendToClassPathForInstrumentation method in the custom class loader must add to the class search path in a thread-safe manner.

Build 23

Disabled TLS_ECDH_* Cipher Suites (JDK-8279164)


The TLS_ECDH_* cipher suites have been disabled by default, by adding "ECDH" to the jdk.tls.disabledAlgorithms security property in the java.security configuration file. The TLS_ECDH_* cipher suites do not preserve forward-secrecy and are rarely used in practice. Note that some TLS_ECDH_* cipher suites were already disabled because they use algorithms that are disabled, such as 3DES and RC4. This action disables the rest. Any attempts to use cipher suites starting with "TLS_ECDH_" will fail with an SSLHandshakeException. Users can, at their own risk, re-enable these cipher suites by removing "ECDH" from the jdk.tls.disabledAlgorithms security property.

IdentityHashMap's Remove and Replace Methods Use Object Identity (JDK-8178355)


The remove(key, value) and replace(key, oldValue, newValue) implementations of IdentityHashMap have been corrected. In previous releases, the value arguments were compared with values in the map using equals. However, IdentityHashMap specifies that all such comparisons should be made using object identity (==). These methods' implementations now conform to the specification.

Do not normalize file paths to Unicode Normalization Format D on macOS (JDK-8289689)


On macOS, file names are no longer normalized to Apple's variant of Unicode Normalization Format D. File names were normalized on HFS+ prior to macOS 10.13, but on APFS on macOS 10.13 and newer this normalization is no longer effected. The previous behavior may be enabled by setting the system property "jdk.nio.path.useNormalizationFormD" to "true".

Added constructors (String, Throwable) and (Throwable) to InvalidParameterException (JDK-8296226)


Constructors InvalidParameterException(String, Throwable) and InvalidParameterException(Throwable) have been added to the java.security.InvalidParameterException class to support easy construction of InvalidParameterException objects with a cause.

Deprecate and Disable Legacy Parallel Class Loading Workaround for Non-Parallel-Capable Class Loaders (JDK-8295673)


Some user-defined older class loaders would workaround a deadlock issue by releasing the class loader lock during the loading process. To prevent these loaders from encountering a “java.lang.LinkageError: attempted duplicate class definition” while loading the same class by parallel threads, the HotSpot Virtual Machine introduced a workaround in JDK 6 that serialized the load attempts, causing the subsequent attempts to wait for the first to complete.

The need for class loaders to work this way was removed in JDK 7 when parallel-capable class loaders were introduced, but the workaround remained in the VM. That workaround is finally being removed and as a first step has been deprecated and disabled by default. If you start seeing "java.lang.LinkageError: attempted duplicate class definition" then you may have an affected legacy class loader. The flag -XX:+EnableWaitForParallelLoad can be used to temporarily restore the old behavior in this release of the JDK, but the legacy class loader will need to be updated for future releases.

See the CSR request (JDK-8295848) for more background and details.

java.net.URL constructors are deprecated (JDK-8294241)


The java.net.URL constructors are deprecated in this release.

Developers are encouraged to use java.net.URI to parse or construct a URL. In cases where an instance of java.net.URL is needed to open a connection, java.net.URI can be used to construct or parse the URL string, possibly calling URI::parseServerAuthority() to validate that the authority component can be parsed as a server-based authority, and then calling URI::toURL() to create the URL instance.

A new method, URL::of(URI, URLStreamHandler) is provided for the advanced usages where there is a need to construct a URL with a given custom stream handler.

See the java.net.URL API documentation [1] for more details [2].

[1] https://download.java.net/java/early_access/jdk20/docs/api/java.base/java/net/URL.html#constructor-summary

[2] https://download.java.net/java/early_access/jdk20/docs/api/java.base/java/net/URL.html#constructor-deprecation

Build 22

Disabled DTLS 1.0 (JDK-8256660)


DTLS 1.0 has been disabled by default, by adding "DTLSv1.0" to the jdk.tls.disabledAlgorithms security property in the java.security configuration file. DTLS 1.0 has weakened over time and lacks support for stronger cipher suites. Any attempts to use DTLSv1.0 will fail with an SSLHandshakeException. Users can, at their own risk, re-enable the version by removing "DTLSv1.0" from the jdk.tls.disabledAlgorithms security property.

The new method Path::getExtension returns the file’s extension (JDK-8057113)


Support for obtaining the file extension of a file path's name is added via a new default method java.nio.file.Path::getExtension. Some examples:

File Name String Extension
"foo.tar.gz" "gz"
"foo.bar" "bar"
"foo." ""
"foo" null
".bar" null

JMX connections use an ObjectInputFilter by default (JDK-8283093)


The default JMX agent now sets an ObjectInputFilter on the RMI connection, to restrict the types that the server will deserialize. This should not affect normal usage of the MBeans in the JDK. Applications which register their own MBeans in the Platform MBeanServer may need to extend the filter to support any additional types that their MBeans accept as parameters. The default filter already covers any type that OpenMBeans and MXBeans might use.

The filter pattern is set in JDK/conf/management/management.properties using the property com.sun.management.jmxremote.serial.filter.pattern. If there are additional Java types that need to be passed, the default can be overridden by running with -Dcom.sun.management.jmxremote.serial.filter.pattern=

Serialization Filtering and the filter pattern format are described in detail in the Core Libraries guide.

Support Unicode 15.0 (JDK-8284842)


This release upgrades Unicode support to 15.0, which includes the following:

The java.lang.Character class supports the Unicode Character Database of 15.0 level, which adds 4,489 characters, for a total of 149,186 characters. These additions include 2 new scripts, for a total of 161 scripts, as well as 20 new emoji characters, and 4,193 CJK (Chinese, Japanese, and Korean) ideographs. The java.text.Bidi and java.text.Normalizer classes support 15.0 level of Unicode Standard Annexes, #9 and #15, respectively. The java.util.regex package supports Extended Grapheme Clusters based on the 15.0 level of Unicode Standard Annex #29 For more detail about Unicode 15.0, refer to the Unicode Consortium's release note.

Build 21

Improved control of G1 concurrent refinement threads (JDK-8137022)


The control of G1 concurrent refinement threads has been completely replaced. The new controller typically allocates fewer threads. It tends to have fewer spikes in refinement thread activity. It also tends to delay refinement, allowing more filtering by the write barrier when there are multiple writes to the same or nearby locations, improving the efficiency of the barrier.

There are a number of command line options used to provide parameter values for the old controller. These aren't relevant to the new controller, and no longer serve any useful purpose. They have all been made obsolete; specifying any of them on the command line will do nothing but print a warning message about the option being obsolete. These arguments are







These options will be removed entirely in some future release. Use of any of these options after that time will terminate startup of the virtual machine.

Support for CLDR Version 42 (JDK-8284840)


Locale data based on Unicode Consortium's CLDR has been upgraded to version 42. For the detailed locale data changes, please refer to the Unicode Consortium's CLDR release notes: https://cldr.unicode.org/index/downloads/cldr-42 Some of the notable changes in the upstream that may affect formatting are:

Build 20

FileChannel positional write is unspecified in APPEND mode (JDK-6924219)


The specification of java.nio.channels.FileChannel is updated to clarify that the effect of attempting to write at a specific position using the FileChannel::write(ByteBuffer,long) method is system-dependent when the channel is open in append mode (java.nio.file.StandardOpenOption.APPEND is passed to FileChannel::open when the channel is opened). In particular, on some operating systems bytes will be written at the given position, while on other operating systems the given position will be ignored and the bytes will be appended to the file.

New JFR Event: jdk.InitialSecurityProperty (JDK-8292177)


A new Java Flight Recorder (JFR) event has been added to record details of initial security properties when loaded via the java.security.Security class.

The new event name is jdk.InitialSecurityProperty and contains the following fields:

Field name Field Description
key Security Property Key
value Corresponding Security Property Value

This new JFR event is enabled by default. The java.security.debug=properties system property will also now print initial security properties to standard error stream. With this new event and the already available 'jdk.SecurityPropertyModification' event (when enabled since it is not enabled by default), a JFR recording can now monitor the initial settings of all security properties and any subsequent changes.

URL constructors called with malformed input may throw MalformedURLException for cases where it wasn't thrown previously (JDK-8293590)


The parsing of input provided to the java.net.URL constructors has changed in this release to be more strict. If the URL constructors are called with malformed input then MalformedURLException may be thrown for cases where it wasn’t thrown previously.

In previous releases, some of the parsing/validation performed by the JDK built-in URLStreamHander implementations was delayed until URL::openConnection or URLConnection::connect was called. Some of these parsing/validation are now performed early, within URL constructors. An exception caused by a malformed URL that would have been delayed until the connection was opened or connected might now cause a MalformedURLException to be thrown at URL construction time.

This change only affects URL instances that delegate to JDK built in stream handler implementations. Only applications relying on JDK built-in stream handlers should be affected. Applications relying on custom third party URLStreamHandler implementations should remain unaffected.

A new JDK specific system property -Djdk.net.url.delayParsing or -Djdk.net.url.delayParsing=true can be specified on the command line to revert to the previous behavior. By default, the property is not set, and the new behavior is in place. The property can be specified on the java command line if unexpected regressions are observed.

This new property is provided for backward compatibility and may be removed in a future release.

GetLocalXXX/SetLocalXXX spec should require suspending target thread (JDK-8288387)


The JVM TI spec of the GetLocalXXX/SetLocalXXX functions has been changed to require the target thread to be either suspended or the current thread. The error code JVMTI_ERROR_THREAD_NOT_SUSPENDED will be returned if this requirement is not satisfied. The JVM TI agents which use the GetLocalXXX/SetLocalXXX API's need to be updated to suspend target thread if it is not the current thread. The full list of impacted JVM TI functions is:

  • GetLocalObject, GetLocalInt, GetLocalLong, GetLocalFloat, GetLocalDouble, GetLocalInstance,
  • SetLocalObject, SetLocalInt, SetLocalLong, SetLocalFloat, SetLocalDouble

Build 17

Thread.suspend/resume changed to throw UnsupportedOperationException (JDK-8249627)


The ability to suspend or resume a Thread with the Thread.suspend() and Thread.resume() methods has been removed in this release. The methods have been changed to throw UnsupportedOperationException. These methods were inherently deadlock prone and have been deprecated since JDK 1.2 (1998). The corresponding methods in ThreadGroup, to suspend or resume a group of threads, were changed to throw UnsupportedOperationException in Java 19.

New JFR Event: jdk.SecurityProviderService (JDK-8254711)


A new Java Flight Recorder (JFR) event has been added to record details of java.security.Provider.getService(String type, String algorithm) calls.

The new event name is jdk.SecurityProviderService and contains the following fields:

Field name Field Description
type Type of Service
algorithm Algorithm Name
provider Security Provider

This event is disabled by default and can be enabled via the JFR configuration files or via standard JFR options.

Thread.Stop changed to throw UnsupportedOperationException (JDK-8289610)


The ability to "stop" a Thread with the Thread.stop() method has been removed in this release. The method has been changed to throw UnsupportedOperationException. Stopping a Thread by causing it to throw java.lang.ThreadDeath was inherently unsafe. The stop method has been deprecated since JDK 1.2 (1998). The corresponding method in ThreadGroup, to "stop" a group of threads, was changed to throw UnsupportedOperationException in Java 19.

As part of this change, java.lang.ThreadDeath has been deprecated, for removal.

Build 16

G1: Disable preventive GCs by default (JDK-8293861)


In JDK 17 G1 added "preventive" garbage collections (GCs): these are speculative garbage collections, with the goal of avoiding costly evacuation failures due to allocation bursts when the heap is almost full.

However, these (speculative) collections have the consequence of additional garbage collection work - as object aging is based on number of GCs with additional GCs cause premature promotion into the old generation - which leads to more data in the old generation, and more garbage collection work to remove these objects. This has been compounded by the current prediction to trigger preventive garbage collections being very conservative; which means these garbage collections are often triggered unnecessarily.

In the majority of cases this feature is a net loss, and as evacuation failures are now handled more quickly, there is no longer any reason for this feature and it has been disabled by default, it may be re-enabled by -XX:+UnlockDiagnosticVMOptions -XX:+G1UsePreventiveGC.

Javac Warns about Type Casts in Compound Assignments with Possible Lossy Conversions (JDK-8244681)


New lint option lossy-conversions has been added to javac to warn about type casts in compound assignments with possible lossy conversions. If the type of the right-hand operand of a compound assignment is not assignment compatible with the type of the variable, a cast is implied and possible lossy conversion may occur.

The new warnings can be suppressed using @SuppressWarnings("lossy-conversions").

Build 15

Grapheme support in BreakIterator (JDK-8291660)


Character boundary analysis in java.text.BreakIterator now conforms to Extended Grapheme Clusters breaks defined in Unicode Consortium's Standard Annex #29. This change will introduce intentional behavioral changes because the old implementation simply breaks at the code point boundaries for the vast majority of characters. For example, this is a String that contains the US flag and a grapheme for a 4-member-family.


This String will be broken into two graphemes with the new implementation:

"🇺🇸", "👨‍👩‍👧‍👦"

whereas the old implementation simply breaks at the code point boundaries:

"🇺", "🇸", "👨", "(zwj)", "👩", "(zwj)", "👧", "(zwj)"‍, "👦" 

where (zwj) denotes ZERO WIDTH JOINER (U+200D).

Build 14

Update Timezone Data to 2022c (JDK-8292579)


This version includes changes from 2022b that merged multiple regions that have the same timestamp data post-1970 into a single time zone database. All time zone IDs remain the same but the merged time zones will point to a shared zone database.

As a result, pre-1970 data may not be compatible with earlier JDK versions. The affected zones are Antarctica/Vostok, Asia/Brunei, Asia/Kuala_Lumpur, Atlantic/Reykjavik, Europe/Amsterdam, Europe/Copenhagen, Europe/Luxembourg, Europe/Monaco, Europe/Oslo, Europe/Stockholm, Indian/Christmas, Indian/Cocos, Indian/Kerguelen, Indian/Mahe, Indian/Reunion, Pacific/Chuuk, Pacific/Funafuti, Pacific/Majuro, Pacific/Pohnpei, Pacific/Wake, Pacific/Wallis, Arctic/Longyearbyen, Atlantic/Jan_Mayen, Iceland, Pacific/Ponape, Pacific/Truk, and Pacific/Yap.

For more details, refer to the announcement of 2022b

Build 11

Throw Error if default java.security file fails to load (JDK-8155246)


A behavioral change has been made in the case where the default conf/security/java.security security configuration file fails to load. In such a scenario, the JDK will now throw an InternalError.

Such a scenario should never occur. The default security file should always be present. Prior to this change, a static and outdated security configuration was loaded.

Build 9

New Implementation Note for LoginModule on Removing Null from a Principals or Credentials set (JDK-8282730)


The Set implementation that holds principals and credentials in a JAAS Subject prohibits null elements and any attempt to add, query, or remove a null element will result in a NullPointerException. This is especially important when trying to remove principals or credentials from the subject at the logout phase but they are null because of a previous failed login. Various JDK LoginModule implementations have been fixed to avoid the exception. An Implementation Note has also been added to the logout() method of the LoginModule interface. Developers should verify and if necessary update any custom LoginModule implementations to be compliant with this implementation advice.

Build 6

Restore Behavior of java.math.BigDecimal.movePointLeft() and movePointRight() on a Zero Argument (JDK-8289260)


When these methods are invoked with a zero argument on a target with a negative scale, they return a result which is numerically the same as the target, but with a different unscaled value and scale.

In earlier releases, they returned a result with the same unscaled value and scale, which was against the specification.

The behavior is unchanged when the target has a non-negative scale or when the argument is not zero.