Hello,

while investigating an issue I've found out that assignment of default value to 
volatile fields slows down object instantiation.

Consider the benchmark:

@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(value = Mode.AverageTime)
@Fork(jvmArgsAppend = {"-Xms2g", "-Xmx2g"})
public class VolatileFieldBenchmark {
  @Benchmark
  public Object explicitInit() {
    return new ExplicitInit();
  }

  @Benchmark
  public Object noInit() {
    return new NoInit();
  }

  private static class ExplicitInit {
    private volatile boolean field = false;
  }
  private static class NoInit {
    private volatile boolean field;
  }
}

This gives the following results as of my machine:

Benchmark Mode Cnt Score Error Units
VolatileFieldBenchmark.explicitInit avgt 40 11.087 ± 0.140 ns/op
VolatileFieldBenchmark.noInit avgt 40 3.367 ± 0.131 ns/op

I've looked into source code of java.base and found out several cases where the 
default value is assigned to volatile field.

Getting rid of such assignements demonstates improvement as of object 
instantiation, e.g. javax.security.auth.Subject:

           Mode Cnt Score Error Units
before avgt 40 35.933 ± 2.647 ns/op
after avgt 40 30.817 ± 2.384 ns/op

As of testing tier1 and tier2 are both ok after the changes.

Best regards,
Sergey Tsypanov
diff --git a/src/java.base/share/classes/java/security/KeyStore.java b/src/java.base/share/classes/java/security/KeyStore.java
--- a/src/java.base/share/classes/java/security/KeyStore.java
+++ b/src/java.base/share/classes/java/security/KeyStore.java
@@ -219,7 +219,7 @@
     private KeyStoreSpi keyStoreSpi;
 
     // Has this keystore been initialized (loaded)?
-    private boolean initialized = false;
+    private boolean initialized;
 
     /**
      * A marker interface for {@code KeyStore}
@@ -264,7 +264,7 @@
         private final char[] password;
         private final String protectionAlgorithm;
         private final AlgorithmParameterSpec protectionParameters;
-        private volatile boolean destroyed = false;
+        private volatile boolean destroyed;
 
         /**
          * Creates a password parameter.
diff --git a/src/java.base/share/classes/java/util/ListResourceBundle.java b/src/java.base/share/classes/java/util/ListResourceBundle.java
--- a/src/java.base/share/classes/java/util/ListResourceBundle.java
+++ b/src/java.base/share/classes/java/util/ListResourceBundle.java
@@ -206,5 +206,5 @@
         lookup = temp;
     }
 
-    private volatile Map<String,Object> lookup = null;
+    private volatile Map<String,Object> lookup;
 }
diff --git a/src/java.base/share/classes/javax/security/auth/Subject.java b/src/java.base/share/classes/javax/security/auth/Subject.java
--- a/src/java.base/share/classes/javax/security/auth/Subject.java
+++ b/src/java.base/share/classes/javax/security/auth/Subject.java
@@ -126,7 +126,7 @@
      *
      * @serial
      */
-    private volatile boolean readOnly = false;
+    private volatile boolean readOnly;
 
     private static final int PRINCIPAL_SET = 1;
     private static final int PUB_CREDENTIAL_SET = 2;
diff --git a/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java b/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java
--- a/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java
+++ b/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java
@@ -71,7 +71,7 @@
 
     // Common working status
 
-    private boolean instantiated = false;
+    private boolean instantiated;
 
     /**
      * Reseed counter of a DRBG instance. A mechanism should increment it
@@ -80,7 +80,7 @@
      *
      * Volatile, will be used in a double checked locking.
      */
-    protected volatile int reseedCounter = 0;
+    protected volatile int reseedCounter;
 
     // Mech features. If not same as below, must be redefined in constructor.
 
diff --git a/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java b/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java
--- a/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java
+++ b/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java
@@ -36,7 +36,7 @@
  */
 final class DTLSOutputRecord extends OutputRecord implements DTLSRecord {
 
-    private DTLSFragmenter fragmenter = null;
+    private DTLSFragmenter fragmenter;
 
     int                 writeEpoch;
 
@@ -44,7 +44,7 @@
     Authenticator       prevWriteAuthenticator;
     SSLWriteCipher      prevWriteCipher;
 
-    private volatile boolean isCloseWaiting = false;
+    private volatile boolean isCloseWaiting;
 
     DTLSOutputRecord(HandshakeHash handshakeHash) {
         super(handshakeHash, SSLWriteCipher.nullDTlsWriteCipher());
diff --git a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java
--- a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java
+++ b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java
@@ -102,11 +102,11 @@
     boolean                                 isResumption;
     SSLSessionImpl                          resumingSession;
     // Session is using stateless resumption
-    boolean                                 statelessResumption = false;
+    boolean                                 statelessResumption;
 
     final Queue<Map.Entry<Byte, ByteBuffer>> delegatedActions;
-    volatile boolean                        taskDelegated = false;
-    volatile Exception                      delegatedThrown = null;
+    volatile boolean                        taskDelegated;
+    volatile Exception                      delegatedThrown;
 
     ProtocolVersion                         negotiatedProtocol;
     CipherSuite                             negotiatedCipherSuite;
diff --git a/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java
--- a/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java
+++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java
@@ -37,11 +37,11 @@
  */
 final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord {
 
-    private HandshakeFragment fragmenter = null;
-    private boolean isTalkingToV2 = false;      // SSLv2Hello
-    private ByteBuffer v2ClientHello = null;    // SSLv2Hello
+    private HandshakeFragment fragmenter;
+    private boolean isTalkingToV2;      // SSLv2Hello
+    private ByteBuffer v2ClientHello;    // SSLv2Hello
 
-    private volatile boolean isCloseWaiting = false;
+    private volatile boolean isCloseWaiting;
 
     SSLEngineOutputRecord(HandshakeHash handshakeHash) {
         super(handshakeHash, SSLWriteCipher.nullTlsWriteCipher());
diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
--- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
@@ -83,8 +83,8 @@
 
     private String                  peerHost;
     private boolean                 autoClose;
-    private boolean                 isConnected = false;
-    private volatile boolean        tlsIsClosed = false;
+    private boolean                 isConnected;
+    private volatile boolean        tlsIsClosed;
 
     private final ReentrantLock     socketLock = new ReentrantLock();
     private final ReentrantLock     handshakeLock = new ReentrantLock();
--- Begin Message ---
Hello,

while investigating an issue I've found out that assignment of default value to 
volatile fields slows down object instantiation.

Consider the benchmark:

@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(value = Mode.AverageTime)
@Fork(jvmArgsAppend = {"-Xms2g", "-Xmx2g"})
public class VolatileFieldBenchmark {
  @Benchmark
  public Object explicitInit() {
    return new ExplicitInit();
  }

  @Benchmark
  public Object noInit() {
    return new NoInit();
  }

  private static class ExplicitInit {
    private volatile boolean field = false;
  }
  private static class NoInit {
    private volatile boolean field;
  }
}

This gives the following results as of my machine:

Benchmark                            Mode  Cnt   Score   Error  Units
VolatileFieldBenchmark.explicitInit  avgt   40  11.087 ± 0.140  ns/op
VolatileFieldBenchmark.noInit        avgt   40   3.367 ± 0.131  ns/op


I've looked into source code of java.base and found out several cases where the 
default value is assigned to volatile field.

Getting rid of such assignements demonstates improvement as of object 
instantiation, e.g. javax.security.auth.Subject:

           Mode  Cnt   Score   Error  Units
before     avgt   40  35.933 ± 2.647  ns/op
after      avgt   40  30.817 ± 2.384  ns/op

As of testing tier1 and tier2 are both ok after the changes.

Best regards,
Sergey Tsypanov
diff --git a/src/java.base/share/classes/java/security/KeyStore.java b/src/java.base/share/classes/java/security/KeyStore.java
--- a/src/java.base/share/classes/java/security/KeyStore.java
+++ b/src/java.base/share/classes/java/security/KeyStore.java
@@ -219,7 +219,7 @@
     private KeyStoreSpi keyStoreSpi;
 
     // Has this keystore been initialized (loaded)?
-    private boolean initialized = false;
+    private boolean initialized;
 
     /**
      * A marker interface for {@code KeyStore}
@@ -264,7 +264,7 @@
         private final char[] password;
         private final String protectionAlgorithm;
         private final AlgorithmParameterSpec protectionParameters;
-        private volatile boolean destroyed = false;
+        private volatile boolean destroyed;
 
         /**
          * Creates a password parameter.
diff --git a/src/java.base/share/classes/java/util/ListResourceBundle.java b/src/java.base/share/classes/java/util/ListResourceBundle.java
--- a/src/java.base/share/classes/java/util/ListResourceBundle.java
+++ b/src/java.base/share/classes/java/util/ListResourceBundle.java
@@ -206,5 +206,5 @@
         lookup = temp;
     }
 
-    private volatile Map<String,Object> lookup = null;
+    private volatile Map<String,Object> lookup;
 }
diff --git a/src/java.base/share/classes/javax/security/auth/Subject.java b/src/java.base/share/classes/javax/security/auth/Subject.java
--- a/src/java.base/share/classes/javax/security/auth/Subject.java
+++ b/src/java.base/share/classes/javax/security/auth/Subject.java
@@ -126,7 +126,7 @@
      *
      * @serial
      */
-    private volatile boolean readOnly = false;
+    private volatile boolean readOnly;
 
     private static final int PRINCIPAL_SET = 1;
     private static final int PUB_CREDENTIAL_SET = 2;
diff --git a/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java b/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java
--- a/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java
+++ b/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java
@@ -71,7 +71,7 @@
 
     // Common working status
 
-    private boolean instantiated = false;
+    private boolean instantiated;
 
     /**
      * Reseed counter of a DRBG instance. A mechanism should increment it
@@ -80,7 +80,7 @@
      *
      * Volatile, will be used in a double checked locking.
      */
-    protected volatile int reseedCounter = 0;
+    protected volatile int reseedCounter;
 
     // Mech features. If not same as below, must be redefined in constructor.
 
diff --git a/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java b/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java
--- a/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java
+++ b/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java
@@ -36,7 +36,7 @@
  */
 final class DTLSOutputRecord extends OutputRecord implements DTLSRecord {
 
-    private DTLSFragmenter fragmenter = null;
+    private DTLSFragmenter fragmenter;
 
     int                 writeEpoch;
 
@@ -44,7 +44,7 @@
     Authenticator       prevWriteAuthenticator;
     SSLWriteCipher      prevWriteCipher;
 
-    private volatile boolean isCloseWaiting = false;
+    private volatile boolean isCloseWaiting;
 
     DTLSOutputRecord(HandshakeHash handshakeHash) {
         super(handshakeHash, SSLWriteCipher.nullDTlsWriteCipher());
diff --git a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java
--- a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java
+++ b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java
@@ -102,11 +102,11 @@
     boolean                                 isResumption;
     SSLSessionImpl                          resumingSession;
     // Session is using stateless resumption
-    boolean                                 statelessResumption = false;
+    boolean                                 statelessResumption;
 
     final Queue<Map.Entry<Byte, ByteBuffer>> delegatedActions;
-    volatile boolean                        taskDelegated = false;
-    volatile Exception                      delegatedThrown = null;
+    volatile boolean                        taskDelegated;
+    volatile Exception                      delegatedThrown;
 
     ProtocolVersion                         negotiatedProtocol;
     CipherSuite                             negotiatedCipherSuite;
diff --git a/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java
--- a/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java
+++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java
@@ -37,11 +37,11 @@
  */
 final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord {
 
-    private HandshakeFragment fragmenter = null;
-    private boolean isTalkingToV2 = false;      // SSLv2Hello
-    private ByteBuffer v2ClientHello = null;    // SSLv2Hello
+    private HandshakeFragment fragmenter;
+    private boolean isTalkingToV2;      // SSLv2Hello
+    private ByteBuffer v2ClientHello;    // SSLv2Hello
 
-    private volatile boolean isCloseWaiting = false;
+    private volatile boolean isCloseWaiting;
 
     SSLEngineOutputRecord(HandshakeHash handshakeHash) {
         super(handshakeHash, SSLWriteCipher.nullTlsWriteCipher());
diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
--- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
@@ -83,8 +83,8 @@
 
     private String                  peerHost;
     private boolean                 autoClose;
-    private boolean                 isConnected = false;
-    private volatile boolean        tlsIsClosed = false;
+    private boolean                 isConnected;
+    private volatile boolean        tlsIsClosed;
 
     private final ReentrantLock     socketLock = new ReentrantLock();
     private final ReentrantLock     handshakeLock = new ReentrantLock();

--- End Message ---

Reply via email to