8221882: Use fiber-friendly java.util.concurrent.locks in JSSE
authorxuelei
Fri, 05 Apr 2019 11:28:23 -0700
changeset 54443 dfba4e321ab3
parent 54442 172f929786ea
child 54444 259b40b4d473
8221882: Use fiber-friendly java.util.concurrent.locks in JSSE Reviewed-by: alanb, dfuchs
src/java.base/share/classes/javax/net/ssl/SSLContext.java
src/java.base/share/classes/javax/net/ssl/SSLServerSocketFactory.java
src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java
src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java
src/java.base/share/classes/sun/security/ssl/BaseSSLSocketImpl.java
src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java
src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java
src/java.base/share/classes/sun/security/ssl/EphemeralKeyManager.java
src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java
src/java.base/share/classes/sun/security/ssl/InputRecord.java
src/java.base/share/classes/sun/security/ssl/OutputRecord.java
src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java
src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java
src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java
src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java
src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java
src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java
src/java.base/share/classes/sun/security/ssl/SunX509KeyManagerImpl.java
src/java.base/share/classes/sun/security/ssl/TransportContext.java
src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java
src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java
--- a/src/java.base/share/classes/javax/net/ssl/SSLContext.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/javax/net/ssl/SSLContext.java	Fri Apr 05 11:28:23 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,8 +26,9 @@
 package javax.net.ssl;
 
 import java.security.*;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.Objects;
-
 import sun.security.jca.GetInstance;
 
 /**
@@ -58,6 +59,20 @@
 
     private final String protocol;
 
+    private static volatile SSLContext defaultContext;
+
+    private static final VarHandle VH_DEFAULT_CONTEXT;
+
+    static {
+        try {
+            VH_DEFAULT_CONTEXT = MethodHandles.lookup()
+                .findStaticVarHandle(
+                    SSLContext.class, "defaultContext", SSLContext.class);
+        } catch (Exception e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
     /**
      * Creates an SSLContext object.
      *
@@ -72,8 +87,6 @@
         this.protocol = protocol;
     }
 
-    private static SSLContext defaultContext;
-
     /**
      * Returns the default SSL context.
      *
@@ -91,12 +104,16 @@
      *   {@link SSLContext#getInstance SSLContext.getInstance()} call fails
      * @since 1.6
      */
-    public static synchronized SSLContext getDefault()
-            throws NoSuchAlgorithmException {
-        if (defaultContext == null) {
-            defaultContext = SSLContext.getInstance("Default");
+    public static SSLContext getDefault() throws NoSuchAlgorithmException {
+        SSLContext temporaryContext = defaultContext;
+        if (temporaryContext == null) {
+            temporaryContext = SSLContext.getInstance("Default");
+            if (!VH_DEFAULT_CONTEXT.compareAndSet(null, temporaryContext)) {
+                temporaryContext = defaultContext;
+            }
         }
-        return defaultContext;
+
+        return temporaryContext;
     }
 
     /**
@@ -111,7 +128,7 @@
      *          {@code SSLPermission("setDefaultSSLContext")}
      * @since 1.6
      */
-    public static synchronized void setDefault(SSLContext context) {
+    public static void setDefault(SSLContext context) {
         if (context == null) {
             throw new NullPointerException();
         }
@@ -119,6 +136,7 @@
         if (sm != null) {
             sm.checkPermission(new SSLPermission("setDefaultSSLContext"));
         }
+
         defaultContext = context;
     }
 
--- a/src/java.base/share/classes/javax/net/ssl/SSLServerSocketFactory.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/javax/net/ssl/SSLServerSocketFactory.java	Fri Apr 05 11:28:23 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,17 +42,7 @@
  * @see SSLServerSocket
  * @author David Brownell
  */
-public abstract class SSLServerSocketFactory extends ServerSocketFactory
-{
-    private static SSLServerSocketFactory theFactory;
-
-    private static boolean propertyChecked;
-
-    private static void log(String msg) {
-        if (SSLSocketFactory.DEBUG) {
-            System.out.println(msg);
-        }
-    }
+public abstract class SSLServerSocketFactory extends ServerSocketFactory {
 
     /**
      * Constructor is used only by subclasses.
@@ -75,39 +65,9 @@
      * @return the default <code>ServerSocketFactory</code>
      * @see SSLContext#getDefault
      */
-    public static synchronized ServerSocketFactory getDefault() {
-        if (theFactory != null) {
-            return theFactory;
-        }
-
-        if (propertyChecked == false) {
-            propertyChecked = true;
-            String clsName = SSLSocketFactory.getSecurityProperty
-                                        ("ssl.ServerSocketFactory.provider");
-            if (clsName != null) {
-                log("setting up default SSLServerSocketFactory");
-                try {
-                    Class<?> cls = null;
-                    try {
-                        cls = Class.forName(clsName);
-                    } catch (ClassNotFoundException e) {
-                        ClassLoader cl = ClassLoader.getSystemClassLoader();
-                        if (cl != null) {
-                            cls = cl.loadClass(clsName);
-                        }
-                    }
-                    log("class " + clsName + " is loaded");
-                    @SuppressWarnings("deprecation")
-                    SSLServerSocketFactory fac = (SSLServerSocketFactory)cls.newInstance();
-                    log("instantiated an instance of class " + clsName);
-                    theFactory = fac;
-                    return fac;
-                } catch (Exception e) {
-                    log("SSLServerSocketFactory instantiation failed: " + e);
-                    theFactory = new DefaultSSLServerSocketFactory(e);
-                    return theFactory;
-                }
-            }
+    public static ServerSocketFactory getDefault() {
+        if (DefaultFactoryHolder.defaultFactory != null) {
+            return DefaultFactoryHolder.defaultFactory;
         }
 
         try {
@@ -156,9 +116,51 @@
      * @see #getDefaultCipherSuites()
      */
     public abstract String [] getSupportedCipherSuites();
+
+    // lazy initialization holder class idiom for static default factory
+    //
+    // See Effective Java Second Edition: Item 71.
+    private static final class DefaultFactoryHolder {
+        private static final SSLServerSocketFactory defaultFactory;
+
+        static {
+            SSLServerSocketFactory mediator = null;
+            String clsName = SSLSocketFactory.getSecurityProperty(
+                    "ssl.ServerSocketFactory.provider");
+            if (clsName != null) {
+                log("setting up default SSLServerSocketFactory");
+                try {
+                    Class<?> cls = null;
+                    try {
+                        cls = Class.forName(clsName);
+                    } catch (ClassNotFoundException e) {
+                        ClassLoader cl = ClassLoader.getSystemClassLoader();
+                        if (cl != null) {
+                            cls = cl.loadClass(clsName);
+                        }
+                    }
+                    log("class " + clsName + " is loaded");
+
+                    mediator = (SSLServerSocketFactory)cls
+                            .getDeclaredConstructor().newInstance();
+                    log("instantiated an instance of class " + clsName);
+                } catch (Exception e) {
+                    log("SSLServerSocketFactory instantiation failed: " + e);
+                    mediator = new DefaultSSLServerSocketFactory(e);
+                }
+            }
+
+            defaultFactory = mediator;
+        }
+
+        private static void log(String msg) {
+            if (SSLSocketFactory.DEBUG) {
+                System.out.println(msg);
+            }
+        }
+    }
 }
 
-
 //
 // The default factory does NOTHING.
 //
--- a/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java	Fri Apr 05 11:28:23 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,31 +42,20 @@
  * @see SSLSocket
  * @author David Brownell
  */
-public abstract class SSLSocketFactory extends SocketFactory
-{
-    private static SSLSocketFactory theFactory;
-
-    private static boolean propertyChecked;
-
+public abstract class SSLSocketFactory extends SocketFactory {
     static final boolean DEBUG;
 
     static {
-        String s = GetPropertyAction.privilegedGetProperty("javax.net.debug", "")
-                .toLowerCase(Locale.ENGLISH);
-
+        String s = GetPropertyAction.privilegedGetProperty(
+                "javax.net.debug", "").toLowerCase(Locale.ENGLISH);
         DEBUG = s.contains("all") || s.contains("ssl");
     }
 
-    private static void log(String msg) {
-        if (DEBUG) {
-            System.out.println(msg);
-        }
-    }
-
     /**
      * Constructor is used only by subclasses.
      */
     public SSLSocketFactory() {
+        // blank
     }
 
     /**
@@ -85,38 +74,9 @@
      * @return the default <code>SocketFactory</code>
      * @see SSLContext#getDefault
      */
-    public static synchronized SocketFactory getDefault() {
-        if (theFactory != null) {
-            return theFactory;
-        }
-
-        if (propertyChecked == false) {
-            propertyChecked = true;
-            String clsName = getSecurityProperty("ssl.SocketFactory.provider");
-            if (clsName != null) {
-                log("setting up default SSLSocketFactory");
-                try {
-                    Class<?> cls = null;
-                    try {
-                        cls = Class.forName(clsName);
-                    } catch (ClassNotFoundException e) {
-                        ClassLoader cl = ClassLoader.getSystemClassLoader();
-                        if (cl != null) {
-                            cls = cl.loadClass(clsName);
-                        }
-                    }
-                    log("class " + clsName + " is loaded");
-                    @SuppressWarnings("deprecation")
-                    SSLSocketFactory fac = (SSLSocketFactory)cls.newInstance();
-                    log("instantiated an instance of class " + clsName);
-                    theFactory = fac;
-                    return fac;
-                } catch (Exception e) {
-                    log("SSLSocketFactory instantiation failed: " + e.toString());
-                    theFactory = new DefaultSSLSocketFactory(e);
-                    return theFactory;
-                }
-            }
+    public static SocketFactory getDefault() {
+        if (DefaultFactoryHolder.defaultFactory != null) {
+            return DefaultFactoryHolder.defaultFactory;
         }
 
         try {
@@ -246,6 +206,49 @@
             boolean autoClose) throws IOException {
         throw new UnsupportedOperationException();
     }
+
+    // lazy initialization holder class idiom for static default factory
+    //
+    // See Effective Java Second Edition: Item 71.
+    private static final class DefaultFactoryHolder {
+        private static final SSLSocketFactory defaultFactory;
+
+        static {
+            SSLSocketFactory mediator = null;
+            String clsName = getSecurityProperty("ssl.SocketFactory.provider");
+            if (clsName != null) {
+                log("setting up default SSLSocketFactory");
+                try {
+                    Class<?> cls = null;
+                    try {
+                        cls = Class.forName(clsName);
+                    } catch (ClassNotFoundException e) {
+                        ClassLoader cl = ClassLoader.getSystemClassLoader();
+                        if (cl != null) {
+                            cls = cl.loadClass(clsName);
+                        }
+                    }
+                    log("class " + clsName + " is loaded");
+
+                    mediator = (SSLSocketFactory)cls
+                            .getDeclaredConstructor().newInstance();
+
+                    log("instantiated an instance of class " + clsName);
+                } catch (Exception e) {
+                    log("SSLSocketFactory instantiation failed: " + e);
+                    mediator = new DefaultSSLSocketFactory(e);
+                }
+            }
+
+            defaultFactory = mediator;
+        }
+
+        private static void log(String msg) {
+            if (DEBUG) {
+                System.out.println(msg);
+            }
+        }
+    }
 }
 
 
--- a/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java	Fri Apr 05 11:28:23 2019 -0700
@@ -57,8 +57,7 @@
 public class HttpsURLConnectionImpl
         extends javax.net.ssl.HttpsURLConnection {
 
-    // NOTE: made protected for plugin so that subclass can set it.
-    protected DelegateHttpsURLConnection delegate;
+    private final DelegateHttpsURLConnection delegate;
 
     HttpsURLConnectionImpl(URL u, Handler handler) throws IOException {
         this(u, null, handler);
@@ -78,13 +77,6 @@
         delegate = new DelegateHttpsURLConnection(url, p, handler, this);
     }
 
-    // NOTE: introduced for plugin
-    // subclass needs to overwrite this to set delegate to
-    // the appropriate delegatee
-    protected HttpsURLConnectionImpl(URL u) throws IOException {
-        super(u);
-    }
-
     /**
      * Create a new HttpClient object, bypassing the cache of
      * HTTP client objects/connections.
@@ -219,11 +211,11 @@
      * - get input, [read input,] get output, [write output]
      */
 
-    public synchronized OutputStream getOutputStream() throws IOException {
+    public OutputStream getOutputStream() throws IOException {
         return delegate.getOutputStream();
     }
 
-    public synchronized InputStream getInputStream() throws IOException {
+    public InputStream getInputStream() throws IOException {
         return delegate.getInputStream();
     }
 
--- a/src/java.base/share/classes/sun/security/ssl/BaseSSLSocketImpl.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/BaseSSLSocketImpl.java	Fri Apr 05 11:28:23 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -632,7 +632,7 @@
     }
 
     @Override
-    public synchronized void setSoTimeout(int timeout) throws SocketException {
+    public void setSoTimeout(int timeout) throws SocketException {
         if (self == this) {
             super.setSoTimeout(timeout);
         } else {
--- a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java	Fri Apr 05 11:28:23 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -58,7 +58,7 @@
     }
 
     @Override
-    public synchronized void close() throws IOException {
+    public void close() throws IOException {
         if (!isClosed) {
             super.close();
         }
--- a/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java	Fri Apr 05 11:28:23 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -58,13 +58,18 @@
     }
 
     @Override
-    public synchronized void close() throws IOException {
-        if (!isClosed) {
-            if (fragmenter != null && fragmenter.hasAlert()) {
-                isCloseWaiting = true;
-            } else {
-                super.close();
+    public void close() throws IOException {
+        recordLock.lock();
+        try {
+            if (!isClosed) {
+                if (fragmenter != null && fragmenter.hasAlert()) {
+                    isCloseWaiting = true;
+                } else {
+                    super.close();
+                }
             }
+        } finally {
+            recordLock.unlock();
         }
     }
 
--- a/src/java.base/share/classes/sun/security/ssl/EphemeralKeyManager.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/EphemeralKeyManager.java	Fri Apr 05 11:28:23 2019 -0700
@@ -26,6 +26,7 @@
 package sun.security.ssl;
 
 import java.security.*;
+import java.util.concurrent.locks.ReentrantLock;
 
 /**
  * The "KeyManager" for ephemeral RSA keys. Ephemeral DH and ECDH keys
@@ -48,6 +49,8 @@
         new EphemeralKeyPair(null),
     };
 
+    private final ReentrantLock cachedKeysLock = new ReentrantLock();
+
     EphemeralKeyManager() {
         // empty
     }
@@ -65,20 +68,32 @@
             index = INDEX_RSA1024;
         }
 
-        synchronized (keys) {
-            KeyPair kp = keys[index].getKeyPair();
-            if (kp == null) {
-                try {
-                    KeyPairGenerator kgen = KeyPairGenerator.getInstance("RSA");
-                    kgen.initialize(length, random);
-                    keys[index] = new EphemeralKeyPair(kgen.genKeyPair());
-                    kp = keys[index].getKeyPair();
-                } catch (Exception e) {
-                    // ignore
-                }
-            }
+        KeyPair kp = keys[index].getKeyPair();
+        if (kp != null) {
             return kp;
         }
+
+        cachedKeysLock.lock();
+        try {
+            // double check
+            kp = keys[index].getKeyPair();
+            if (kp != null) {
+                return kp;
+            }
+
+            try {
+                KeyPairGenerator kgen = KeyPairGenerator.getInstance("RSA");
+                kgen.initialize(length, random);
+                keys[index] = new EphemeralKeyPair(kgen.genKeyPair());
+                kp = keys[index].getKeyPair();
+            } catch (Exception e) {
+                // ignore
+            }
+        } finally {
+            cachedKeysLock.unlock();
+        }
+
+        return kp;
     }
 
     /**
--- a/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java	Fri Apr 05 11:28:23 2019 -0700
@@ -30,6 +30,7 @@
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
 import java.util.Arrays;
+import java.util.concurrent.locks.ReentrantLock;
 import static sun.security.ssl.ClientHello.ClientHelloMessage;
 
 /**
@@ -45,6 +46,8 @@
         private volatile D13HelloCookieManager d13HelloCookieManager;
         private volatile T13HelloCookieManager t13HelloCookieManager;
 
+        private final ReentrantLock managerLock = new ReentrantLock();
+
         Builder(SecureRandom secureRandom) {
             this.secureRandom = secureRandom;
         }
@@ -56,11 +59,14 @@
                         return d13HelloCookieManager;
                     }
 
-                    synchronized (this) {
+                    managerLock.lock();
+                    try {
                         if (d13HelloCookieManager == null) {
                             d13HelloCookieManager =
                                     new D13HelloCookieManager(secureRandom);
                         }
+                    } finally {
+                        managerLock.unlock();
                     }
 
                     return d13HelloCookieManager;
@@ -69,11 +75,14 @@
                         return d10HelloCookieManager;
                     }
 
-                    synchronized (this) {
+                    managerLock.lock();
+                    try {
                         if (d10HelloCookieManager == null) {
                             d10HelloCookieManager =
                                     new D10HelloCookieManager(secureRandom);
                         }
+                    } finally {
+                        managerLock.unlock();
                     }
 
                     return d10HelloCookieManager;
@@ -84,11 +93,14 @@
                         return t13HelloCookieManager;
                     }
 
-                    synchronized (this) {
+                    managerLock.lock();
+                    try {
                         if (t13HelloCookieManager == null) {
                             t13HelloCookieManager =
                                     new T13HelloCookieManager(secureRandom);
                         }
+                    } finally {
+                        managerLock.unlock();
                     }
 
                     return t13HelloCookieManager;
@@ -114,6 +126,8 @@
         private byte[]      cookieSecret;
         private byte[]      legacySecret;
 
+        private final ReentrantLock d10ManagerLock = new ReentrantLock();
+
         D10HelloCookieManager(SecureRandom secureRandom) {
             this.secureRandom = secureRandom;
 
@@ -131,7 +145,8 @@
             int version;
             byte[] secret;
 
-            synchronized (this) {
+            d10ManagerLock.lock();
+            try {
                 version = cookieVersion;
                 secret = cookieSecret;
 
@@ -142,6 +157,8 @@
                 }
 
                 cookieVersion++;
+            } finally {
+                d10ManagerLock.unlock();
             }
 
             MessageDigest md;
@@ -168,12 +185,15 @@
             }
 
             byte[] secret;
-            synchronized (this) {
+            d10ManagerLock.lock();
+            try {
                 if (((cookieVersion >> 24) & 0xFF) == cookie[0]) {
                     secret = cookieSecret;
                 } else {
                     secret = legacySecret;  // including out of window cookies
                 }
+            } finally {
+                d10ManagerLock.unlock();
             }
 
             MessageDigest md;
@@ -218,6 +238,8 @@
         private final byte[]    cookieSecret;
         private final byte[]    legacySecret;
 
+        private final ReentrantLock t13ManagerLock = new ReentrantLock();
+
         T13HelloCookieManager(SecureRandom secureRandom) {
             this.secureRandom = secureRandom;
             this.cookieVersion = secureRandom.nextInt();
@@ -234,7 +256,8 @@
             int version;
             byte[] secret;
 
-            synchronized (this) {
+            t13ManagerLock.lock();
+            try {
                 version = cookieVersion;
                 secret = cookieSecret;
 
@@ -245,6 +268,8 @@
                 }
 
                 cookieVersion++;        // allow wrapped version number
+            } finally {
+                t13ManagerLock.unlock();
             }
 
             MessageDigest md;
@@ -313,12 +338,15 @@
                     Arrays.copyOfRange(cookie, 3 + hashLen, cookie.length);
 
             byte[] secret;
-            synchronized (this) {
+            t13ManagerLock.lock();
+            try {
                 if ((byte)((cookieVersion >> 24) & 0xFF) == cookie[2]) {
                     secret = cookieSecret;
                 } else {
                     secret = legacySecret;  // including out of window cookies
                 }
+            } finally {
+                t13ManagerLock.unlock();
             }
 
             MessageDigest md;
--- a/src/java.base/share/classes/sun/security/ssl/InputRecord.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/InputRecord.java	Fri Apr 05 11:28:23 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
 import java.io.OutputStream;
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
+import java.util.concurrent.locks.ReentrantLock;
 import javax.crypto.BadPaddingException;
 import sun.security.ssl.SSLCipher.SSLReadCipher;
 
@@ -43,10 +44,10 @@
 abstract class InputRecord implements Record, Closeable {
     SSLReadCipher       readCipher;
     // Needed for KeyUpdate, used after Handshake.Finished
-    TransportContext            tc;
+    TransportContext    tc;
 
     final HandshakeHash handshakeHash;
-    boolean             isClosed;
+    volatile boolean    isClosed;
 
     // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello
     // and the first message we read is a ClientHello in V2 format, we convert
@@ -56,6 +57,8 @@
     // fragment size
     int                 fragmentSize;
 
+    final ReentrantLock recordLock = new ReentrantLock();
+
     InputRecord(HandshakeHash handshakeHash, SSLReadCipher readCipher) {
         this.readCipher = readCipher;
         this.helloVersion = ProtocolVersion.TLS10;
@@ -92,14 +95,19 @@
      * and flag the record as holding no data.
      */
     @Override
-    public synchronized void close() throws IOException {
-        if (!isClosed) {
-            isClosed = true;
-            readCipher.dispose();
+    public void close() throws IOException {
+        recordLock.lock();
+        try {
+            if (!isClosed) {
+                isClosed = true;
+                readCipher.dispose();
+            }
+        } finally {
+            recordLock.unlock();
         }
     }
 
-    synchronized boolean isClosed() {
+    boolean isClosed() {
         return isClosed;
     }
 
--- a/src/java.base/share/classes/sun/security/ssl/OutputRecord.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/OutputRecord.java	Fri Apr 05 11:28:23 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
+import java.util.concurrent.locks.ReentrantLock;
 import sun.security.ssl.SSLCipher.SSLWriteCipher;
 
 /**
@@ -68,6 +69,8 @@
     // closed or not?
     volatile boolean            isClosed;
 
+    final ReentrantLock recordLock = new ReentrantLock();
+
     /*
      * Mappings from V3 cipher suite encodings to their pure V2 equivalents.
      * This is taken from the SSL V3 specification, Appendix E.
@@ -89,15 +92,25 @@
         // Please set packetSize and protocolVersion in the implementation.
     }
 
-    synchronized void setVersion(ProtocolVersion protocolVersion) {
-        this.protocolVersion = protocolVersion;
+    void setVersion(ProtocolVersion protocolVersion) {
+        recordLock.lock();
+        try {
+            this.protocolVersion = protocolVersion;
+        } finally {
+            recordLock.unlock();
+        }
     }
 
     /*
      * Updates helloVersion of this record.
      */
-    synchronized void setHelloVersion(ProtocolVersion helloVersion) {
-        this.helloVersion = helloVersion;
+    void setHelloVersion(ProtocolVersion helloVersion) {
+        recordLock.lock();
+        try {
+            this.helloVersion = helloVersion;
+        } finally {
+            recordLock.unlock();
+        }
     }
 
     /*
@@ -108,9 +121,14 @@
         return false;
     }
 
-    synchronized boolean seqNumIsHuge() {
-        return (writeCipher.authenticator != null) &&
+    boolean seqNumIsHuge() {
+        recordLock.lock();
+        try {
+            return (writeCipher.authenticator != null) &&
                         writeCipher.authenticator.seqNumIsHuge();
+        } finally {
+            recordLock.unlock();
+        }
     }
 
     // SSLEngine and SSLSocket
@@ -148,68 +166,93 @@
     }
 
     // Change write ciphers, may use change_cipher_spec record.
-    synchronized void changeWriteCiphers(SSLWriteCipher writeCipher,
+    void changeWriteCiphers(SSLWriteCipher writeCipher,
             boolean useChangeCipherSpec) throws IOException {
-        if (isClosed()) {
-            if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
-                SSLLogger.warning("outbound has closed, ignore outbound " +
-                    "change_cipher_spec message");
+        recordLock.lock();
+        try {
+            if (isClosed()) {
+                if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+                    SSLLogger.warning("outbound has closed, ignore outbound " +
+                        "change_cipher_spec message");
+                }
+                return;
+            }
+
+            if (useChangeCipherSpec) {
+                encodeChangeCipherSpec();
             }
-            return;
-        }
 
-        if (useChangeCipherSpec) {
-            encodeChangeCipherSpec();
+            /*
+             * Dispose of any intermediate state in the underlying cipher.
+             * For PKCS11 ciphers, this will release any attached sessions,
+             * and thus make finalization faster.
+             *
+             * Since MAC's doFinal() is called for every SSL/TLS packet, it's
+             * not necessary to do the same with MAC's.
+             */
+            writeCipher.dispose();
+
+            this.writeCipher = writeCipher;
+            this.isFirstAppOutputRecord = true;
+        } finally {
+            recordLock.unlock();
         }
-
-        /*
-         * Dispose of any intermediate state in the underlying cipher.
-         * For PKCS11 ciphers, this will release any attached sessions,
-         * and thus make finalization faster.
-         *
-         * Since MAC's doFinal() is called for every SSL/TLS packet, it's
-         * not necessary to do the same with MAC's.
-         */
-        writeCipher.dispose();
-
-        this.writeCipher = writeCipher;
-        this.isFirstAppOutputRecord = true;
     }
 
     // Change write ciphers using key_update handshake message.
-    synchronized void changeWriteCiphers(SSLWriteCipher writeCipher,
+    void changeWriteCiphers(SSLWriteCipher writeCipher,
             byte keyUpdateRequest) throws IOException {
-        if (isClosed()) {
-            if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
-                SSLLogger.warning("outbound has closed, ignore outbound " +
-                    "key_update handshake message");
+        recordLock.lock();
+        try {
+            if (isClosed()) {
+                if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+                    SSLLogger.warning("outbound has closed, ignore outbound " +
+                        "key_update handshake message");
+                }
+                return;
             }
-            return;
-        }
 
-        // encode the handshake message, KeyUpdate
-        byte[] hm = HANDSHAKE_MESSAGE_KEY_UPDATE.clone();
-        hm[hm.length - 1] = keyUpdateRequest;
-        encodeHandshake(hm, 0, hm.length);
-        flush();
+            // encode the handshake message, KeyUpdate
+            byte[] hm = HANDSHAKE_MESSAGE_KEY_UPDATE.clone();
+            hm[hm.length - 1] = keyUpdateRequest;
+            encodeHandshake(hm, 0, hm.length);
+            flush();
 
-        // Dispose of any intermediate state in the underlying cipher.
-        writeCipher.dispose();
+            // Dispose of any intermediate state in the underlying cipher.
+            writeCipher.dispose();
 
-        this.writeCipher = writeCipher;
-        this.isFirstAppOutputRecord = true;
+            this.writeCipher = writeCipher;
+            this.isFirstAppOutputRecord = true;
+        } finally {
+            recordLock.unlock();
+        }
     }
 
-    synchronized void changePacketSize(int packetSize) {
-        this.packetSize = packetSize;
+    void changePacketSize(int packetSize) {
+        recordLock.lock();
+        try {
+            this.packetSize = packetSize;
+        } finally {
+            recordLock.unlock();
+        }
     }
 
-    synchronized void changeFragmentSize(int fragmentSize) {
-        this.fragmentSize = fragmentSize;
+    void changeFragmentSize(int fragmentSize) {
+        recordLock.lock();
+        try {
+            this.fragmentSize = fragmentSize;
+        } finally {
+            recordLock.unlock();
+        }
     }
 
-    synchronized int getMaxPacketSize() {
-        return packetSize;
+    int getMaxPacketSize() {
+        recordLock.lock();
+        try {
+            return packetSize;
+        } finally {
+            recordLock.unlock();
+        }
     }
 
     // apply to DTLS SSLEngine
@@ -228,13 +271,18 @@
     }
 
     @Override
-    public synchronized void close() throws IOException {
-        if (isClosed) {
-            return;
+    public void close() throws IOException {
+        recordLock.lock();
+        try {
+            if (isClosed) {
+                return;
+            }
+
+            isClosed = true;
+            writeCipher.dispose();
+        } finally {
+            recordLock.unlock();
         }
-
-        isClosed = true;
-        writeCipher.dispose();
     }
 
     boolean isClosed() {
--- a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Fri Apr 05 11:28:23 2019 -0700
@@ -30,6 +30,7 @@
 import java.security.*;
 import java.security.cert.*;
 import java.util.*;
+import java.util.concurrent.locks.ReentrantLock;
 import javax.net.ssl.*;
 import sun.security.action.GetPropertyAction;
 import sun.security.provider.certpath.AlgorithmChecker;
@@ -69,6 +70,8 @@
 
     private volatile StatusResponseManager statusResponseManager;
 
+    private final ReentrantLock contextLock = new ReentrantLock();
+
     SSLContextImpl() {
         ephemeralKeyManager = new EphemeralKeyManager();
         clientCache = new SSLSessionContextImpl();
@@ -230,11 +233,14 @@
     // Used for DTLS in server mode only.
     HelloCookieManager getHelloCookieManager(ProtocolVersion protocolVersion) {
         if (helloCookieManagerBuilder == null) {
-            synchronized (this) {
+            contextLock.lock();
+            try {
                 if (helloCookieManagerBuilder == null) {
                     helloCookieManagerBuilder =
                             new HelloCookieManager.Builder(secureRandom);
                 }
+            } finally {
+                contextLock.unlock();
             }
         }
 
@@ -243,7 +249,8 @@
 
     StatusResponseManager getStatusResponseManager() {
         if (serverEnableStapling && statusResponseManager == null) {
-            synchronized (this) {
+            contextLock.lock();
+            try {
                 if (statusResponseManager == null) {
                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) {
                         SSLLogger.finest(
@@ -251,6 +258,8 @@
                     }
                     statusResponseManager = new StatusResponseManager();
                 }
+            } finally {
+                contextLock.unlock();
             }
         }
 
--- a/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java	Fri Apr 05 11:28:23 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
 import java.security.PrivilegedExceptionAction;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.BiFunction;
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLEngineResult;
@@ -54,6 +55,7 @@
 final class SSLEngineImpl extends SSLEngine implements SSLTransport {
     private final SSLContextImpl        sslContext;
     final TransportContext              conContext;
+    private final ReentrantLock         engineLock = new ReentrantLock();
 
     /**
      * Constructor for an SSLEngine from SSLContext, without
@@ -93,57 +95,68 @@
     }
 
     @Override
-    public synchronized void beginHandshake() throws SSLException {
-        if (conContext.isUnsureMode) {
-            throw new IllegalStateException(
-                    "Client/Server mode has not yet been set.");
-        }
-
+    public void beginHandshake() throws SSLException {
+        engineLock.lock();
         try {
-            conContext.kickstart();
-        } catch (IOException ioe) {
-            throw conContext.fatal(Alert.HANDSHAKE_FAILURE,
-                "Couldn't kickstart handshaking", ioe);
-        } catch (Exception ex) {     // including RuntimeException
-            throw conContext.fatal(Alert.INTERNAL_ERROR,
-                "Fail to begin handshake", ex);
+            if (conContext.isUnsureMode) {
+                throw new IllegalStateException(
+                        "Client/Server mode has not yet been set.");
+            }
+
+            try {
+                conContext.kickstart();
+            } catch (IOException ioe) {
+                throw conContext.fatal(Alert.HANDSHAKE_FAILURE,
+                    "Couldn't kickstart handshaking", ioe);
+            } catch (Exception ex) {     // including RuntimeException
+                throw conContext.fatal(Alert.INTERNAL_ERROR,
+                    "Fail to begin handshake", ex);
+            }
+        } finally {
+            engineLock.unlock();
         }
     }
 
     @Override
-    public synchronized SSLEngineResult wrap(ByteBuffer[] appData,
+    public SSLEngineResult wrap(ByteBuffer[] appData,
             int offset, int length, ByteBuffer netData) throws SSLException {
         return wrap(appData, offset, length, new ByteBuffer[]{ netData }, 0, 1);
     }
 
     // @Override
-    public synchronized SSLEngineResult wrap(
+    public SSLEngineResult wrap(
         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException {
 
-        if (conContext.isUnsureMode) {
-            throw new IllegalStateException(
-                    "Client/Server mode has not yet been set.");
-        }
-
-        // See if the handshaker needs to report back some SSLException.
-        checkTaskThrown();
-
-        // check parameters
-        checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
-
+        engineLock.lock();
         try {
-            return writeRecord(
-                srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
-        } catch (SSLProtocolException spe) {
-            // may be an unexpected handshake message
-            throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, spe);
-        } catch (IOException ioe) {
-            throw conContext.fatal(Alert.INTERNAL_ERROR,
-                "problem wrapping app data", ioe);
-        } catch (Exception ex) {     // including RuntimeException
-            throw conContext.fatal(Alert.INTERNAL_ERROR,
-                "Fail to wrap application data", ex);
+            if (conContext.isUnsureMode) {
+                throw new IllegalStateException(
+                        "Client/Server mode has not yet been set.");
+            }
+
+            // See if the handshaker needs to report back some SSLException.
+            checkTaskThrown();
+
+            // check parameters
+            checkParams(srcs, srcsOffset, srcsLength,
+                    dsts, dstsOffset, dstsLength);
+
+            try {
+                return writeRecord(
+                    srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
+            } catch (SSLProtocolException spe) {
+                // may be an unexpected handshake message
+                throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, spe);
+            } catch (IOException ioe) {
+                throw conContext.fatal(Alert.INTERNAL_ERROR,
+                    "problem wrapping app data", ioe);
+            } catch (Exception ex) {     // including RuntimeException
+                throw conContext.fatal(Alert.INTERNAL_ERROR,
+                    "Fail to wrap application data", ex);
+            }
+        } finally {
+            engineLock.unlock();
         }
     }
 
@@ -428,47 +441,53 @@
     }
 
     @Override
-    public synchronized SSLEngineResult unwrap(ByteBuffer src,
+    public SSLEngineResult unwrap(ByteBuffer src,
             ByteBuffer[] dsts, int offset, int length) throws SSLException {
         return unwrap(
                 new ByteBuffer[]{src}, 0, 1, dsts, offset, length);
     }
 
     // @Override
-    public synchronized SSLEngineResult unwrap(
+    public SSLEngineResult unwrap(
         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException {
 
-        if (conContext.isUnsureMode) {
-            throw new IllegalStateException(
-                    "Client/Server mode has not yet been set.");
-        }
-
-        // See if the handshaker needs to report back some SSLException.
-        checkTaskThrown();
-
-        // check parameters
-        checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
-
+        engineLock.lock();
         try {
-            return readRecord(
-                srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
-        } catch (SSLProtocolException spe) {
-            // may be an unexpected handshake message
-            throw conContext.fatal(Alert.UNEXPECTED_MESSAGE,
-                    spe.getMessage(), spe);
-        } catch (IOException ioe) {
-            /*
-             * Don't reset position so it looks like we didn't
-             * consume anything.  We did consume something, and it
-             * got us into this situation, so report that much back.
-             * Our days of consuming are now over anyway.
-             */
-            throw conContext.fatal(Alert.INTERNAL_ERROR,
-                    "problem unwrapping net record", ioe);
-        } catch (Exception ex) {     // including RuntimeException
-            throw conContext.fatal(Alert.INTERNAL_ERROR,
-                "Fail to unwrap network record", ex);
+            if (conContext.isUnsureMode) {
+                throw new IllegalStateException(
+                        "Client/Server mode has not yet been set.");
+            }
+
+            // See if the handshaker needs to report back some SSLException.
+            checkTaskThrown();
+
+            // check parameters
+            checkParams(srcs, srcsOffset, srcsLength,
+                    dsts, dstsOffset, dstsLength);
+
+            try {
+                return readRecord(
+                    srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
+            } catch (SSLProtocolException spe) {
+                // may be an unexpected handshake message
+                throw conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+                        spe.getMessage(), spe);
+            } catch (IOException ioe) {
+                /*
+                 * Don't reset position so it looks like we didn't
+                 * consume anything.  We did consume something, and it
+                 * got us into this situation, so report that much back.
+                 * Our days of consuming are now over anyway.
+                 */
+                throw conContext.fatal(Alert.INTERNAL_ERROR,
+                        "problem unwrapping net record", ioe);
+            } catch (Exception ex) {     // including RuntimeException
+                throw conContext.fatal(Alert.INTERNAL_ERROR,
+                    "Fail to unwrap network record", ex);
+            }
+        } finally {
+            engineLock.unlock();
         }
     }
 
@@ -703,61 +722,87 @@
     }
 
     @Override
-    public synchronized Runnable getDelegatedTask() {
-        if (conContext.handshakeContext != null && // PRE or POST handshake
-                !conContext.handshakeContext.taskDelegated &&
-                !conContext.handshakeContext.delegatedActions.isEmpty()) {
-            conContext.handshakeContext.taskDelegated = true;
-            return new DelegatedTask(this);
+    public Runnable getDelegatedTask() {
+        engineLock.lock();
+        try {
+            if (conContext.handshakeContext != null && // PRE or POST handshake
+                    !conContext.handshakeContext.taskDelegated &&
+                    !conContext.handshakeContext.delegatedActions.isEmpty()) {
+                conContext.handshakeContext.taskDelegated = true;
+                return new DelegatedTask(this);
+            }
+        } finally {
+            engineLock.unlock();
         }
 
         return null;
     }
 
     @Override
-    public synchronized void closeInbound() throws SSLException {
-        if (isInboundDone()) {
-            return;
-        }
+    public void closeInbound() throws SSLException {
+        engineLock.lock();
+        try {
+            if (isInboundDone()) {
+                return;
+            }
 
-        if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
-            SSLLogger.finest("Closing inbound of SSLEngine");
-        }
+            if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+                SSLLogger.finest("Closing inbound of SSLEngine");
+            }
 
-        // Is it ready to close inbound?
-        //
-        // No need to throw exception if the initial handshake is not started.
-        if (!conContext.isInputCloseNotified &&
-            (conContext.isNegotiated || conContext.handshakeContext != null)) {
+            // Is it ready to close inbound?
+            //
+            // No exception if the initial handshake is not started.
+            if (!conContext.isInputCloseNotified &&
+                (conContext.isNegotiated ||
+                    conContext.handshakeContext != null)) {
 
-            throw conContext.fatal(Alert.INTERNAL_ERROR,
-                    "closing inbound before receiving peer's close_notify");
+                throw conContext.fatal(Alert.INTERNAL_ERROR,
+                        "closing inbound before receiving peer's close_notify");
+            }
+
+            conContext.closeInbound();
+        } finally {
+            engineLock.unlock();
         }
-
-        conContext.closeInbound();
     }
 
     @Override
-    public synchronized boolean isInboundDone() {
-        return conContext.isInboundClosed();
+    public boolean isInboundDone() {
+        engineLock.lock();
+        try {
+            return conContext.isInboundClosed();
+        } finally {
+            engineLock.unlock();
+        }
     }
 
     @Override
-    public synchronized void closeOutbound() {
-        if (conContext.isOutboundClosed()) {
-            return;
-        }
+    public void closeOutbound() {
+        engineLock.lock();
+        try {
+            if (conContext.isOutboundClosed()) {
+                return;
+            }
 
-        if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
-            SSLLogger.finest("Closing outbound of SSLEngine");
+            if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+                SSLLogger.finest("Closing outbound of SSLEngine");
+            }
+
+            conContext.closeOutbound();
+        } finally {
+            engineLock.unlock();
         }
-
-        conContext.closeOutbound();
     }
 
     @Override
-    public synchronized boolean isOutboundDone() {
-        return conContext.isOutboundDone();
+    public boolean isOutboundDone() {
+        engineLock.lock();
+        try {
+            return conContext.isOutboundDone();
+        } finally {
+            engineLock.unlock();
+        }
     }
 
     @Override
@@ -766,14 +811,24 @@
     }
 
     @Override
-    public synchronized String[] getEnabledCipherSuites() {
-        return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites);
+    public String[] getEnabledCipherSuites() {
+        engineLock.lock();
+        try {
+            return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites);
+        } finally {
+            engineLock.unlock();
+        }
     }
 
     @Override
-    public synchronized void setEnabledCipherSuites(String[] suites) {
-        conContext.sslConfig.enabledCipherSuites =
-                CipherSuite.validValuesOf(suites);
+    public void setEnabledCipherSuites(String[] suites) {
+        engineLock.lock();
+        try {
+            conContext.sslConfig.enabledCipherSuites =
+                    CipherSuite.validValuesOf(suites);
+        } finally {
+            engineLock.unlock();
+        }
     }
 
     @Override
@@ -783,119 +838,214 @@
     }
 
     @Override
-    public synchronized String[] getEnabledProtocols() {
-        return ProtocolVersion.toStringArray(
-                conContext.sslConfig.enabledProtocols);
-    }
-
-    @Override
-    public synchronized void setEnabledProtocols(String[] protocols) {
-        if (protocols == null) {
-            throw new IllegalArgumentException("Protocols cannot be null");
+    public String[] getEnabledProtocols() {
+        engineLock.lock();
+        try {
+            return ProtocolVersion.toStringArray(
+                    conContext.sslConfig.enabledProtocols);
+        } finally {
+            engineLock.unlock();
         }
-
-        conContext.sslConfig.enabledProtocols =
-                ProtocolVersion.namesOf(protocols);
     }
 
     @Override
-    public synchronized SSLSession getSession() {
-        return conContext.conSession;
-    }
+    public void setEnabledProtocols(String[] protocols) {
+        engineLock.lock();
+        try {
+            if (protocols == null) {
+                throw new IllegalArgumentException("Protocols cannot be null");
+            }
 
-    @Override
-    public synchronized SSLSession getHandshakeSession() {
-        return conContext.handshakeContext == null ?
-                null : conContext.handshakeContext.handshakeSession;
+            conContext.sslConfig.enabledProtocols =
+                    ProtocolVersion.namesOf(protocols);
+        } finally {
+            engineLock.unlock();
+        }
     }
 
     @Override
-    public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
-        return conContext.getHandshakeStatus();
+    public SSLSession getSession() {
+        engineLock.lock();
+        try {
+            return conContext.conSession;
+        } finally {
+            engineLock.unlock();
+        }
     }
 
     @Override
-    public synchronized void setUseClientMode(boolean mode) {
-        conContext.setUseClientMode(mode);
-    }
-
-    @Override
-    public synchronized boolean getUseClientMode() {
-        return conContext.sslConfig.isClientMode;
+    public SSLSession getHandshakeSession() {
+        engineLock.lock();
+        try {
+            return conContext.handshakeContext == null ?
+                    null : conContext.handshakeContext.handshakeSession;
+        } finally {
+            engineLock.unlock();
+        }
     }
 
     @Override
-    public synchronized void setNeedClientAuth(boolean need) {
-        conContext.sslConfig.clientAuthType =
-                (need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
-                        ClientAuthType.CLIENT_AUTH_NONE);
+    public SSLEngineResult.HandshakeStatus getHandshakeStatus() {
+        engineLock.lock();
+        try {
+            return conContext.getHandshakeStatus();
+        } finally {
+            engineLock.unlock();
+        }
     }
 
     @Override
-    public synchronized boolean getNeedClientAuth() {
-        return (conContext.sslConfig.clientAuthType ==
-                        ClientAuthType.CLIENT_AUTH_REQUIRED);
-    }
-
-    @Override
-    public synchronized void setWantClientAuth(boolean want) {
-        conContext.sslConfig.clientAuthType =
-                (want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
-                        ClientAuthType.CLIENT_AUTH_NONE);
+    public void setUseClientMode(boolean mode) {
+        engineLock.lock();
+        try {
+            conContext.setUseClientMode(mode);
+        } finally {
+            engineLock.unlock();
+        }
     }
 
     @Override
-    public synchronized boolean getWantClientAuth() {
-        return (conContext.sslConfig.clientAuthType ==
-                        ClientAuthType.CLIENT_AUTH_REQUESTED);
-    }
-
-    @Override
-    public synchronized void setEnableSessionCreation(boolean flag) {
-        conContext.sslConfig.enableSessionCreation = flag;
+    public boolean getUseClientMode() {
+        engineLock.lock();
+        try {
+            return conContext.sslConfig.isClientMode;
+        } finally {
+            engineLock.unlock();
+        }
     }
 
     @Override
-    public synchronized boolean getEnableSessionCreation() {
-        return conContext.sslConfig.enableSessionCreation;
+    public void setNeedClientAuth(boolean need) {
+        engineLock.lock();
+        try {
+            conContext.sslConfig.clientAuthType =
+                    (need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
+                            ClientAuthType.CLIENT_AUTH_NONE);
+        } finally {
+            engineLock.unlock();
+        }
     }
 
     @Override
-    public synchronized SSLParameters getSSLParameters() {
-        return conContext.sslConfig.getSSLParameters();
-    }
-
-    @Override
-    public synchronized void setSSLParameters(SSLParameters params) {
-        conContext.sslConfig.setSSLParameters(params);
-
-        if (conContext.sslConfig.maximumPacketSize != 0) {
-            conContext.outputRecord.changePacketSize(
-                    conContext.sslConfig.maximumPacketSize);
+    public boolean getNeedClientAuth() {
+        engineLock.lock();
+        try {
+            return (conContext.sslConfig.clientAuthType ==
+                            ClientAuthType.CLIENT_AUTH_REQUIRED);
+        } finally {
+            engineLock.unlock();
         }
     }
 
     @Override
-    public synchronized String getApplicationProtocol() {
-        return conContext.applicationProtocol;
+    public void setWantClientAuth(boolean want) {
+        engineLock.lock();
+        try {
+            conContext.sslConfig.clientAuthType =
+                    (want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
+                            ClientAuthType.CLIENT_AUTH_NONE);
+        } finally {
+            engineLock.unlock();
+        }
+    }
+
+    @Override
+    public boolean getWantClientAuth() {
+        engineLock.lock();
+        try {
+            return (conContext.sslConfig.clientAuthType ==
+                            ClientAuthType.CLIENT_AUTH_REQUESTED);
+        } finally {
+            engineLock.unlock();
+        }
+    }
+
+    @Override
+    public void setEnableSessionCreation(boolean flag) {
+        engineLock.lock();
+        try {
+            conContext.sslConfig.enableSessionCreation = flag;
+        } finally {
+            engineLock.unlock();
+        }
+    }
+
+    @Override
+    public boolean getEnableSessionCreation() {
+        engineLock.lock();
+        try {
+            return conContext.sslConfig.enableSessionCreation;
+        } finally {
+            engineLock.unlock();
+        }
     }
 
     @Override
-    public synchronized String getHandshakeApplicationProtocol() {
-        return conContext.handshakeContext == null ?
-                null : conContext.handshakeContext.applicationProtocol;
+    public SSLParameters getSSLParameters() {
+        engineLock.lock();
+        try {
+            return conContext.sslConfig.getSSLParameters();
+        } finally {
+            engineLock.unlock();
+        }
+   }
+
+    @Override
+    public void setSSLParameters(SSLParameters params) {
+        engineLock.lock();
+        try {
+            conContext.sslConfig.setSSLParameters(params);
+
+            if (conContext.sslConfig.maximumPacketSize != 0) {
+                conContext.outputRecord.changePacketSize(
+                        conContext.sslConfig.maximumPacketSize);
+            }
+        } finally {
+            engineLock.unlock();
+        }
+   }
+
+    @Override
+    public String getApplicationProtocol() {
+        engineLock.lock();
+        try {
+            return conContext.applicationProtocol;
+        } finally {
+            engineLock.unlock();
+        }
     }
 
     @Override
-    public synchronized void setHandshakeApplicationProtocolSelector(
-            BiFunction<SSLEngine, List<String>, String> selector) {
-        conContext.sslConfig.engineAPSelector = selector;
+    public String getHandshakeApplicationProtocol() {
+        engineLock.lock();
+        try {
+            return conContext.handshakeContext == null ?
+                    null : conContext.handshakeContext.applicationProtocol;
+        } finally {
+            engineLock.unlock();
+        }
     }
 
     @Override
-    public synchronized BiFunction<SSLEngine, List<String>, String>
+    public void setHandshakeApplicationProtocolSelector(
+            BiFunction<SSLEngine, List<String>, String> selector) {
+        engineLock.lock();
+        try {
+            conContext.sslConfig.engineAPSelector = selector;
+        } finally {
+            engineLock.unlock();
+        }
+    }
+
+    @Override
+    public BiFunction<SSLEngine, List<String>, String>
             getHandshakeApplicationProtocolSelector() {
-        return conContext.sslConfig.engineAPSelector;
+        engineLock.lock();
+        try {
+            return conContext.sslConfig.engineAPSelector;
+        } finally {
+            engineLock.unlock();
+        }
     }
 
     @Override
@@ -909,38 +1059,42 @@
      * null, report back the Exception that happened in the delegated
      * task(s).
      */
-    private synchronized void checkTaskThrown() throws SSLException {
+    private void checkTaskThrown() throws SSLException {
 
         Exception exc = null;
-
-        // First check the handshake context.
-        HandshakeContext hc = conContext.handshakeContext;
-        if ((hc != null) && (hc.delegatedThrown != null)) {
-            exc = hc.delegatedThrown;
-            hc.delegatedThrown = null;
-        }
+        engineLock.lock();
+        try {
+            // First check the handshake context.
+            HandshakeContext hc = conContext.handshakeContext;
+            if ((hc != null) && (hc.delegatedThrown != null)) {
+                exc = hc.delegatedThrown;
+                hc.delegatedThrown = null;
+            }
 
-        /*
-         * hc.delegatedThrown and conContext.delegatedThrown are most likely
-         * the same, but it's possible we could have had a non-fatal
-         * exception and thus the new HandshakeContext is still valid
-         * (alert warning).  If so, then we may have a secondary exception
-         * waiting to be reported from the TransportContext, so we will
-         * need to clear that on a successive call.  Otherwise, clear it now.
-         */
-        if (conContext.delegatedThrown != null) {
-            if (exc != null) {
-                // hc object comparison
-                if (conContext.delegatedThrown == exc) {
-                    // clear if/only if both are the same
+            /*
+             * hc.delegatedThrown and conContext.delegatedThrown are most
+             * likely the same, but it's possible we could have had a non-fatal
+             * exception and thus the new HandshakeContext is still valid
+             * (alert warning).  If so, then we may have a secondary exception
+             * waiting to be reported from the TransportContext, so we will
+             * need to clear that on a successive call. Otherwise, clear it now.
+             */
+            if (conContext.delegatedThrown != null) {
+                if (exc != null) {
+                    // hc object comparison
+                    if (conContext.delegatedThrown == exc) {
+                        // clear if/only if both are the same
+                        conContext.delegatedThrown = null;
+                    } // otherwise report the hc delegatedThrown
+                } else {
+                    // Nothing waiting in HandshakeContext, but one is in the
+                    // TransportContext.
+                    exc = conContext.delegatedThrown;
                     conContext.delegatedThrown = null;
-                } // otherwise report the hc delegatedThrown
-            } else {
-                // Nothing waiting in HandshakeContext, but one is in the
-                // TransportContext.
-                exc = conContext.delegatedThrown;
-                conContext.delegatedThrown = null;
+                }
             }
+        } finally {
+            engineLock.unlock();
         }
 
         // Anything to report?
@@ -998,7 +1152,8 @@
 
         @Override
         public void run() {
-            synchronized (engine) {
+            engine.engineLock.lock();
+            try {
                 HandshakeContext hc = engine.conContext.handshakeContext;
                 if (hc == null || hc.delegatedActions.isEmpty()) {
                     return;
@@ -1055,6 +1210,8 @@
                 if (hc != null) {
                     hc.taskDelegated = false;
                 }
+            } finally {
+                engine.engineLock.unlock();
             }
         }
 
--- a/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java	Fri Apr 05 11:28:23 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,13 +51,18 @@
     }
 
     @Override
-    public synchronized void close() throws IOException {
-        if (!isClosed) {
-            if (fragmenter != null && fragmenter.hasAlert()) {
-                isCloseWaiting = true;
-            } else {
-                super.close();
+    public void close() throws IOException {
+        recordLock.lock();
+        try {
+            if (!isClosed) {
+                if (fragmenter != null && fragmenter.hasAlert()) {
+                    isCloseWaiting = true;
+                } else {
+                    super.close();
+                }
             }
+        } finally {
+            recordLock.unlock();
         }
     }
 
--- a/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java	Fri Apr 05 11:28:23 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.Socket;
+import java.util.concurrent.locks.ReentrantLock;
 import javax.net.ssl.SSLParameters;
 import javax.net.ssl.SSLServerSocket;
 
@@ -56,6 +57,7 @@
 final class SSLServerSocketImpl extends SSLServerSocket {
     private final SSLContextImpl        sslContext;
     private final SSLConfiguration      sslConfig;
+    private final ReentrantLock         serverSocketLock = new ReentrantLock();
 
     SSLServerSocketImpl(SSLContextImpl sslContext) throws IOException {
 
@@ -84,14 +86,24 @@
     }
 
     @Override
-    public synchronized String[] getEnabledCipherSuites() {
-        return CipherSuite.namesOf(sslConfig.enabledCipherSuites);
+    public String[] getEnabledCipherSuites() {
+        serverSocketLock.lock();
+        try {
+            return CipherSuite.namesOf(sslConfig.enabledCipherSuites);
+        } finally {
+            serverSocketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized void setEnabledCipherSuites(String[] suites) {
-        sslConfig.enabledCipherSuites =
-                CipherSuite.validValuesOf(suites);
+    public void setEnabledCipherSuites(String[] suites) {
+        serverSocketLock.lock();
+        try {
+            sslConfig.enabledCipherSuites =
+                    CipherSuite.validValuesOf(suites);
+        } finally {
+            serverSocketLock.unlock();
+        }
     }
 
     @Override
@@ -106,93 +118,153 @@
     }
 
     @Override
-    public synchronized String[] getEnabledProtocols() {
-        return ProtocolVersion.toStringArray(sslConfig.enabledProtocols);
+    public String[] getEnabledProtocols() {
+        serverSocketLock.lock();
+        try {
+            return ProtocolVersion.toStringArray(sslConfig.enabledProtocols);
+        } finally {
+            serverSocketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized void setEnabledProtocols(String[] protocols) {
-        if (protocols == null) {
-            throw new IllegalArgumentException("Protocols cannot be null");
-        }
-
-        sslConfig.enabledProtocols = ProtocolVersion.namesOf(protocols);
-    }
+    public void setEnabledProtocols(String[] protocols) {
+        serverSocketLock.lock();
+        try {
+            if (protocols == null) {
+                throw new IllegalArgumentException("Protocols cannot be null");
+            }
 
-    @Override
-    public synchronized void setNeedClientAuth(boolean need) {
-        sslConfig.clientAuthType =
-                (need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
-                        ClientAuthType.CLIENT_AUTH_NONE);
-    }
-
-    @Override
-    public synchronized boolean getNeedClientAuth() {
-        return (sslConfig.clientAuthType ==
-                        ClientAuthType.CLIENT_AUTH_REQUIRED);
+            sslConfig.enabledProtocols = ProtocolVersion.namesOf(protocols);
+        } finally {
+            serverSocketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized void setWantClientAuth(boolean want) {
-        sslConfig.clientAuthType =
-                (want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
-                        ClientAuthType.CLIENT_AUTH_NONE);
-    }
-
-    @Override
-    public synchronized boolean getWantClientAuth() {
-        return (sslConfig.clientAuthType ==
-                        ClientAuthType.CLIENT_AUTH_REQUESTED);
+    public void setNeedClientAuth(boolean need) {
+        serverSocketLock.lock();
+        try {
+            sslConfig.clientAuthType =
+                    (need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
+                            ClientAuthType.CLIENT_AUTH_NONE);
+        } finally {
+            serverSocketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized void setUseClientMode(boolean useClientMode) {
-        /*
-         * If we need to change the client mode and the enabled
-         * protocols and cipher suites haven't specifically been
-         * set by the user, change them to the corresponding
-         * default ones.
-         */
-        if (sslConfig.isClientMode != useClientMode) {
-            if (sslContext.isDefaultProtocolVesions(
-                    sslConfig.enabledProtocols)) {
-                sslConfig.enabledProtocols =
-                        sslContext.getDefaultProtocolVersions(!useClientMode);
-            }
+    public boolean getNeedClientAuth() {
+        serverSocketLock.lock();
+        try {
+            return (sslConfig.clientAuthType ==
+                        ClientAuthType.CLIENT_AUTH_REQUIRED);
+        } finally {
+            serverSocketLock.unlock();
+        }
+    }
 
-            if (sslContext.isDefaultCipherSuiteList(
-                    sslConfig.enabledCipherSuites)) {
-                sslConfig.enabledCipherSuites =
-                        sslContext.getDefaultCipherSuites(!useClientMode);
-            }
+    @Override
+    public void setWantClientAuth(boolean want) {
+        serverSocketLock.lock();
+        try {
+            sslConfig.clientAuthType =
+                    (want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
+                            ClientAuthType.CLIENT_AUTH_NONE);
+        } finally {
+            serverSocketLock.unlock();
+        }
+    }
 
-            sslConfig.isClientMode = useClientMode;
+    @Override
+    public boolean getWantClientAuth() {
+        serverSocketLock.lock();
+        try {
+            return (sslConfig.clientAuthType ==
+                        ClientAuthType.CLIENT_AUTH_REQUESTED);
+        } finally {
+            serverSocketLock.unlock();
         }
     }
 
     @Override
-    public synchronized boolean getUseClientMode() {
-        return sslConfig.isClientMode;
-    }
+    public void setUseClientMode(boolean useClientMode) {
+        serverSocketLock.lock();
+        try {
+            /*
+             * If we need to change the client mode and the enabled
+             * protocols and cipher suites haven't specifically been
+             * set by the user, change them to the corresponding
+             * default ones.
+             */
+            if (sslConfig.isClientMode != useClientMode) {
+                if (sslContext.isDefaultProtocolVesions(
+                        sslConfig.enabledProtocols)) {
+                    sslConfig.enabledProtocols =
+                        sslContext.getDefaultProtocolVersions(!useClientMode);
+                }
 
-    @Override
-    public synchronized void setEnableSessionCreation(boolean flag) {
-        sslConfig.enableSessionCreation = flag;
+                if (sslContext.isDefaultCipherSuiteList(
+                        sslConfig.enabledCipherSuites)) {
+                    sslConfig.enabledCipherSuites =
+                        sslContext.getDefaultCipherSuites(!useClientMode);
+                }
+
+                sslConfig.isClientMode = useClientMode;
+            }
+        } finally {
+            serverSocketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized boolean getEnableSessionCreation() {
-        return sslConfig.enableSessionCreation;
+    public boolean getUseClientMode() {
+        serverSocketLock.lock();
+        try {
+            return sslConfig.isClientMode;
+        } finally {
+            serverSocketLock.unlock();
+        }
+    }
+
+    @Override
+    public void setEnableSessionCreation(boolean flag) {
+        serverSocketLock.lock();
+        try {
+            sslConfig.enableSessionCreation = flag;
+        } finally {
+            serverSocketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized SSLParameters getSSLParameters() {
-        return sslConfig.getSSLParameters();
+    public boolean getEnableSessionCreation() {
+        serverSocketLock.lock();
+        try {
+            return sslConfig.enableSessionCreation;
+        } finally {
+            serverSocketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized void setSSLParameters(SSLParameters params) {
-        sslConfig.setSSLParameters(params);
+    public SSLParameters getSSLParameters() {
+        serverSocketLock.lock();
+        try {
+            return sslConfig.getSSLParameters();
+        } finally {
+            serverSocketLock.unlock();
+        }
+    }
+
+    @Override
+    public void setSSLParameters(SSLParameters params) {
+        serverSocketLock.lock();
+        try {
+            sslConfig.setSSLParameters(params);
+        } finally {
+            serverSocketLock.unlock();
+        }
     }
 
     @Override
--- a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java	Fri Apr 05 11:28:23 2019 -0700
@@ -38,6 +38,7 @@
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.locks.ReentrantLock;
 import javax.crypto.SecretKey;
 import javax.net.ssl.ExtendedSSLSession;
 import javax.net.ssl.SNIServerName;
@@ -133,7 +134,9 @@
 
     // The endpoint identification algorithm used to check certificates
     // in this session.
-    private final String              identificationProtocol;
+    private final String        identificationProtocol;
+
+    private final ReentrantLock sessionLock = new ReentrantLock();
 
     /*
      * Create a new non-rejoinable session, using the default (null)
@@ -289,15 +292,22 @@
         return resumptionMasterSecret;
     }
 
-    synchronized SecretKey getPreSharedKey() {
-        return preSharedKey;
+    SecretKey getPreSharedKey() {
+        sessionLock.lock();
+        try {
+            return preSharedKey;
+        } finally {
+            sessionLock.unlock();
+        }
     }
 
-    synchronized SecretKey consumePreSharedKey() {
+    SecretKey consumePreSharedKey() {
+        sessionLock.lock();
         try {
             return preSharedKey;
         } finally {
             preSharedKey = null;
+            sessionLock.unlock();
         }
     }
 
@@ -313,11 +323,13 @@
      * be used once. This method will return the identity and then clear it
      * so it cannot be used again.
      */
-    synchronized byte[] consumePskIdentity() {
+    byte[] consumePskIdentity() {
+        sessionLock.lock();
         try {
             return pskIdentity;
         } finally {
             pskIdentity = null;
+            sessionLock.unlock();
         }
     }
 
@@ -393,8 +405,13 @@
     }
 
     @Override
-    public synchronized boolean isValid() {
-        return isRejoinable();
+    public boolean isValid() {
+        sessionLock.lock();
+        try {
+            return isRejoinable();
+        } finally {
+            sessionLock.unlock();
+        }
     }
 
     /**
@@ -777,29 +794,35 @@
      * no connections will be able to rejoin this session.
      */
     @Override
-    public synchronized void invalidate() {
-        //
-        // Can't invalidate the NULL session -- this would be
-        // attempted when we get a handshaking error on a brand
-        // new connection, with no "real" session yet.
-        //
-        if (this == nullSession) {
-            return;
-        }
+    public void invalidate() {
+        sessionLock.lock();
+        try {
+            //
+            // Can't invalidate the NULL session -- this would be
+            // attempted when we get a handshaking error on a brand
+            // new connection, with no "real" session yet.
+            //
+            if (this == nullSession) {
+                return;
+            }
 
-        if (context != null) {
-            context.remove(sessionId);
-            context = null;
-        }
-        if (invalidated) {
-            return;
-        }
-        invalidated = true;
-        if (SSLLogger.isOn && SSLLogger.isOn("session")) {
-             SSLLogger.finest("Invalidated session:  " + this);
-        }
-        for (SSLSessionImpl child : childSessions) {
-            child.invalidate();
+            if (context != null) {
+                context.remove(sessionId);
+                context = null;
+            }
+
+            if (invalidated) {
+                return;
+            }
+            invalidated = true;
+            if (SSLLogger.isOn && SSLLogger.isOn("session")) {
+                 SSLLogger.finest("Invalidated session:  " + this);
+            }
+            for (SSLSessionImpl child : childSessions) {
+                child.invalidate();
+            }
+        } finally {
+            sessionLock.unlock();
         }
     }
 
@@ -912,8 +935,13 @@
      * Expand the buffer size of both SSL/TLS network packet and
      * application data.
      */
-    protected synchronized void expandBufferSizes() {
-        acceptLargeFragments = true;
+    protected void expandBufferSizes() {
+        sessionLock.lock();
+        try {
+            acceptLargeFragments = true;
+        } finally {
+            sessionLock.unlock();
+        }
     }
 
     /**
@@ -921,30 +949,35 @@
      * when using this session.
      */
     @Override
-    public synchronized int getPacketBufferSize() {
-        // Use the bigger packet size calculated from maximumPacketSize
-        // and negotiatedMaxFragLen.
-        int packetSize = 0;
-        if (negotiatedMaxFragLen > 0) {
-            packetSize = cipherSuite.calculatePacketSize(
-                    negotiatedMaxFragLen, protocolVersion,
-                    protocolVersion.isDTLS);
-        }
+    public int getPacketBufferSize() {
+        sessionLock.lock();
+        try {
+            // Use the bigger packet size calculated from maximumPacketSize
+            // and negotiatedMaxFragLen.
+            int packetSize = 0;
+            if (negotiatedMaxFragLen > 0) {
+                packetSize = cipherSuite.calculatePacketSize(
+                        negotiatedMaxFragLen, protocolVersion,
+                        protocolVersion.isDTLS);
+            }
 
-        if (maximumPacketSize > 0) {
-            return (maximumPacketSize > packetSize) ?
-                    maximumPacketSize : packetSize;
-        }
+            if (maximumPacketSize > 0) {
+                return (maximumPacketSize > packetSize) ?
+                        maximumPacketSize : packetSize;
+            }
+
+            if (packetSize != 0) {
+               return packetSize;
+            }
 
-        if (packetSize != 0) {
-           return packetSize;
-        }
-
-        if (protocolVersion.isDTLS) {
-            return DTLSRecord.maxRecordSize;
-        } else {
-            return acceptLargeFragments ?
-                    SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize;
+            if (protocolVersion.isDTLS) {
+                return DTLSRecord.maxRecordSize;
+            } else {
+                return acceptLargeFragments ?
+                        SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize;
+            }
+        } finally {
+            sessionLock.unlock();
         }
     }
 
@@ -953,31 +986,36 @@
      * expected when using this session.
      */
     @Override
-    public synchronized int getApplicationBufferSize() {
-        // Use the bigger fragment size calculated from maximumPacketSize
-        // and negotiatedMaxFragLen.
-        int fragmentSize = 0;
-        if (maximumPacketSize > 0) {
-            fragmentSize = cipherSuite.calculateFragSize(
-                    maximumPacketSize, protocolVersion,
-                    protocolVersion.isDTLS);
-        }
+    public int getApplicationBufferSize() {
+        sessionLock.lock();
+        try {
+            // Use the bigger fragment size calculated from maximumPacketSize
+            // and negotiatedMaxFragLen.
+            int fragmentSize = 0;
+            if (maximumPacketSize > 0) {
+                fragmentSize = cipherSuite.calculateFragSize(
+                        maximumPacketSize, protocolVersion,
+                        protocolVersion.isDTLS);
+            }
 
-        if (negotiatedMaxFragLen > 0) {
-            return (negotiatedMaxFragLen > fragmentSize) ?
-                    negotiatedMaxFragLen : fragmentSize;
-        }
+            if (negotiatedMaxFragLen > 0) {
+                return (negotiatedMaxFragLen > fragmentSize) ?
+                        negotiatedMaxFragLen : fragmentSize;
+            }
+
+            if (fragmentSize != 0) {
+                return fragmentSize;
+            }
 
-        if (fragmentSize != 0) {
-            return fragmentSize;
-        }
-
-        if (protocolVersion.isDTLS) {
-            return Record.maxDataSize;
-        } else {
-            int maxPacketSize = acceptLargeFragments ?
-                        SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize;
-            return (maxPacketSize - SSLRecord.headerSize);
+            if (protocolVersion.isDTLS) {
+                return Record.maxDataSize;
+            } else {
+                int maxPacketSize = acceptLargeFragments ?
+                            SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize;
+                return (maxPacketSize - SSLRecord.headerSize);
+            }
+        } finally {
+            sessionLock.unlock();
         }
     }
 
@@ -989,10 +1027,14 @@
      *         the negotiated maximum fragment length, or {@code -1} if
      *         no such length has been negotiated.
      */
-    synchronized void setNegotiatedMaxFragSize(
+    void setNegotiatedMaxFragSize(
             int negotiatedMaxFragLen) {
-
-        this.negotiatedMaxFragLen = negotiatedMaxFragLen;
+        sessionLock.lock();
+        try {
+            this.negotiatedMaxFragLen = negotiatedMaxFragLen;
+        } finally {
+            sessionLock.unlock();
+        }
     }
 
     /**
@@ -1002,16 +1044,31 @@
      * @return the negotiated maximum fragment length, or {@code -1} if
      *         no such length has been negotiated.
      */
-    synchronized int getNegotiatedMaxFragSize() {
-        return negotiatedMaxFragLen;
+    int getNegotiatedMaxFragSize() {
+        sessionLock.lock();
+        try {
+            return negotiatedMaxFragLen;
+        } finally {
+            sessionLock.unlock();
+        }
     }
 
-    synchronized void setMaximumPacketSize(int maximumPacketSize) {
-        this.maximumPacketSize = maximumPacketSize;
+    void setMaximumPacketSize(int maximumPacketSize) {
+        sessionLock.lock();
+        try {
+            this.maximumPacketSize = maximumPacketSize;
+        } finally {
+            sessionLock.unlock();
+        }
     }
 
-    synchronized int getMaximumPacketSize() {
-        return maximumPacketSize;
+    int getMaximumPacketSize() {
+        sessionLock.lock();
+        try {
+            return maximumPacketSize;
+        } finally {
+            sessionLock.unlock();
+        }
     }
 
     /**
--- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java	Fri Apr 05 11:28:23 2019 -0700
@@ -38,6 +38,7 @@
 import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
 import java.util.List;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.BiFunction;
 import javax.net.ssl.HandshakeCompletedListener;
 import javax.net.ssl.SSLException;
@@ -84,6 +85,9 @@
     private boolean                 isConnected = false;
     private volatile boolean        tlsIsClosed = false;
 
+    private final ReentrantLock     socketLock = new ReentrantLock();
+    private final ReentrantLock     handshakeLock = new ReentrantLock();
+
     /*
      * Is the local name service trustworthy?
      *
@@ -292,14 +296,25 @@
     }
 
     @Override
-    public synchronized String[] getEnabledCipherSuites() {
-        return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites);
+    public String[] getEnabledCipherSuites() {
+        socketLock.lock();
+        try {
+            return CipherSuite.namesOf(
+                    conContext.sslConfig.enabledCipherSuites);
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized void setEnabledCipherSuites(String[] suites) {
-        conContext.sslConfig.enabledCipherSuites =
-                CipherSuite.validValuesOf(suites);
+    public void setEnabledCipherSuites(String[] suites) {
+        socketLock.lock();
+        try {
+            conContext.sslConfig.enabledCipherSuites =
+                    CipherSuite.validValuesOf(suites);
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     @Override
@@ -309,19 +324,29 @@
     }
 
     @Override
-    public synchronized String[] getEnabledProtocols() {
-        return ProtocolVersion.toStringArray(
-                conContext.sslConfig.enabledProtocols);
+    public String[] getEnabledProtocols() {
+        socketLock.lock();
+        try {
+            return ProtocolVersion.toStringArray(
+                    conContext.sslConfig.enabledProtocols);
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized void setEnabledProtocols(String[] protocols) {
+    public void setEnabledProtocols(String[] protocols) {
         if (protocols == null) {
             throw new IllegalArgumentException("Protocols cannot be null");
         }
 
-        conContext.sslConfig.enabledProtocols =
-                ProtocolVersion.namesOf(protocols);
+        socketLock.lock();
+        try {
+            conContext.sslConfig.enabledProtocols =
+                    ProtocolVersion.namesOf(protocols);
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     @Override
@@ -341,29 +366,44 @@
     }
 
     @Override
-    public synchronized SSLSession getHandshakeSession() {
-        return conContext.handshakeContext == null ?
-                null : conContext.handshakeContext.handshakeSession;
+    public SSLSession getHandshakeSession() {
+        socketLock.lock();
+        try {
+            return conContext.handshakeContext == null ?
+                    null : conContext.handshakeContext.handshakeSession;
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized void addHandshakeCompletedListener(
+    public void addHandshakeCompletedListener(
             HandshakeCompletedListener listener) {
         if (listener == null) {
             throw new IllegalArgumentException("listener is null");
         }
 
-        conContext.sslConfig.addHandshakeCompletedListener(listener);
+        socketLock.lock();
+        try {
+            conContext.sslConfig.addHandshakeCompletedListener(listener);
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized void removeHandshakeCompletedListener(
+    public void removeHandshakeCompletedListener(
             HandshakeCompletedListener listener) {
         if (listener == null) {
             throw new IllegalArgumentException("listener is null");
         }
 
-        conContext.sslConfig.removeHandshakeCompletedListener(listener);
+        socketLock.lock();
+        try {
+            conContext.sslConfig.removeHandshakeCompletedListener(listener);
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     @Override
@@ -377,7 +417,8 @@
             throw new SocketException("Socket has been closed or broken");
         }
 
-        synchronized (conContext) {     // handshake lock
+        handshakeLock.lock();
+        try {
             // double check the context status
             if (conContext.isBroken || conContext.isInboundClosed() ||
                     conContext.isOutboundClosed()) {
@@ -400,53 +441,95 @@
             } catch (Exception oe) {    // including RuntimeException
                 handleException(oe);
             }
+        } finally {
+            handshakeLock.unlock();
+        }
+    }
+
+    @Override
+    public void setUseClientMode(boolean mode) {
+        socketLock.lock();
+        try {
+            conContext.setUseClientMode(mode);
+        } finally {
+            socketLock.unlock();
+        }
+    }
+
+    @Override
+    public boolean getUseClientMode() {
+        socketLock.lock();
+        try {
+            return conContext.sslConfig.isClientMode;
+        } finally {
+            socketLock.unlock();
+        }
+    }
+
+    @Override
+    public void setNeedClientAuth(boolean need) {
+        socketLock.lock();
+        try {
+            conContext.sslConfig.clientAuthType =
+                    (need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
+                            ClientAuthType.CLIENT_AUTH_NONE);
+        } finally {
+            socketLock.unlock();
         }
     }
 
     @Override
-    public synchronized void setUseClientMode(boolean mode) {
-        conContext.setUseClientMode(mode);
+    public boolean getNeedClientAuth() {
+        socketLock.lock();
+        try {
+            return (conContext.sslConfig.clientAuthType ==
+                        ClientAuthType.CLIENT_AUTH_REQUIRED);
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized boolean getUseClientMode() {
-        return conContext.sslConfig.isClientMode;
-    }
-
-    @Override
-    public synchronized void setNeedClientAuth(boolean need) {
-        conContext.sslConfig.clientAuthType =
-                (need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
-                        ClientAuthType.CLIENT_AUTH_NONE);
+    public void setWantClientAuth(boolean want) {
+        socketLock.lock();
+        try {
+            conContext.sslConfig.clientAuthType =
+                    (want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
+                            ClientAuthType.CLIENT_AUTH_NONE);
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized boolean getNeedClientAuth() {
-        return (conContext.sslConfig.clientAuthType ==
-                        ClientAuthType.CLIENT_AUTH_REQUIRED);
-    }
-
-    @Override
-    public synchronized void setWantClientAuth(boolean want) {
-        conContext.sslConfig.clientAuthType =
-                (want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
-                        ClientAuthType.CLIENT_AUTH_NONE);
+    public boolean getWantClientAuth() {
+        socketLock.lock();
+        try {
+            return (conContext.sslConfig.clientAuthType ==
+                        ClientAuthType.CLIENT_AUTH_REQUESTED);
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized boolean getWantClientAuth() {
-        return (conContext.sslConfig.clientAuthType ==
-                        ClientAuthType.CLIENT_AUTH_REQUESTED);
+    public void setEnableSessionCreation(boolean flag) {
+        socketLock.lock();
+        try {
+            conContext.sslConfig.enableSessionCreation = flag;
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized void setEnableSessionCreation(boolean flag) {
-        conContext.sslConfig.enableSessionCreation = flag;
-    }
-
-    @Override
-    public synchronized boolean getEnableSessionCreation() {
-        return conContext.sslConfig.enableSessionCreation;
+    public boolean getEnableSessionCreation() {
+        socketLock.lock();
+        try {
+            return conContext.sslConfig.enableSessionCreation;
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     @Override
@@ -535,8 +618,9 @@
 
         // Need a lock here so that the user_canceled alert and the
         // close_notify alert can be delivered together.
+        conContext.outputRecord.recordLock.lock();
         try {
-            synchronized (conContext.outputRecord) {
+            try {
                 // send a user_canceled alert if needed.
                 if (useUserCanceled) {
                     conContext.warning(Alert.USER_CANCELED);
@@ -544,15 +628,17 @@
 
                 // send a close_notify alert
                 conContext.warning(Alert.CLOSE_NOTIFY);
+            } finally {
+                if (!conContext.isOutboundClosed()) {
+                    conContext.outputRecord.close();
+                }
+
+                if ((autoClose || !isLayered()) && !super.isOutputShutdown()) {
+                    super.shutdownOutput();
+                }
             }
         } finally {
-            if (!conContext.isOutboundClosed()) {
-                conContext.outputRecord.close();
-            }
-
-            if ((autoClose || !isLayered()) && !super.isOutputShutdown()) {
-                super.shutdownOutput();
-            }
+            conContext.outputRecord.recordLock.unlock();
         }
 
         if (!isInputShutdown()) {
@@ -681,20 +767,25 @@
     }
 
     @Override
-    public synchronized InputStream getInputStream() throws IOException {
-        if (isClosed()) {
-            throw new SocketException("Socket is closed");
-        }
+    public InputStream getInputStream() throws IOException {
+        socketLock.lock();
+        try {
+            if (isClosed()) {
+                throw new SocketException("Socket is closed");
+            }
 
-        if (!isConnected) {
-            throw new SocketException("Socket is not connected");
-        }
+            if (!isConnected) {
+                throw new SocketException("Socket is not connected");
+            }
 
-        if (conContext.isInboundClosed() || isInputShutdown()) {
-            throw new SocketException("Socket input is already shutdown");
+            if (conContext.isInboundClosed() || isInputShutdown()) {
+                throw new SocketException("Socket input is already shutdown");
+            }
+
+            return appInput;
+        } finally {
+            socketLock.unlock();
         }
-
-        return appInput;
     }
 
     private void ensureNegotiated() throws IOException {
@@ -703,7 +794,8 @@
             return;
         }
 
-        synchronized (conContext) {     // handshake lock
+        handshakeLock.lock();
+        try {
             // double check the context status
             if (conContext.isNegotiated || conContext.isBroken ||
                     conContext.isInboundClosed() ||
@@ -712,6 +804,8 @@
             }
 
             startHandshake();
+        } finally {
+            handshakeLock.unlock();
         }
     }
 
@@ -729,6 +823,9 @@
         // Is application data available in the stream?
         private volatile boolean appDataIsAvailable;
 
+        // reading lock
+        private final ReentrantLock readLock = new ReentrantLock();
+
         AppInputStream() {
             this.appDataIsAvailable = false;
             this.buffer = ByteBuffer.allocate(4096);
@@ -807,7 +904,8 @@
             //
             // Note that the receiving and processing of post-handshake message
             // are also synchronized with the read lock.
-            synchronized (this) {
+            readLock.lock();
+            try {
                 int remains = available();
                 if (remains > 0) {
                     int howmany = Math.min(remains, len);
@@ -839,6 +937,8 @@
                     // dummy for compiler
                     return -1;
                 }
+            } finally {
+                readLock.unlock();
             }
         }
 
@@ -850,19 +950,24 @@
          * things simpler.
          */
         @Override
-        public synchronized long skip(long n) throws IOException {
+        public long skip(long n) throws IOException {
             // dummy array used to implement skip()
             byte[] skipArray = new byte[256];
+            long skipped = 0;
 
-            long skipped = 0;
-            while (n > 0) {
-                int len = (int)Math.min(n, skipArray.length);
-                int r = read(skipArray, 0, len);
-                if (r <= 0) {
-                    break;
+            readLock.lock();
+            try {
+                while (n > 0) {
+                    int len = (int)Math.min(n, skipArray.length);
+                    int r = read(skipArray, 0, len);
+                    if (r <= 0) {
+                        break;
+                    }
+                    n -= r;
+                    skipped += r;
                 }
-                n -= r;
-                skipped += r;
+            } finally {
+                readLock.unlock();
             }
 
             return skipped;
@@ -910,8 +1015,18 @@
          * Try the best to use up the input records so as to close the
          * socket gracefully, without impact the performance too much.
          */
-        private synchronized void deplete() {
-            if (!conContext.isInboundClosed()) {
+        private void deplete() {
+            if (conContext.isInboundClosed()) {
+                return;
+            }
+
+            readLock.lock();
+            try {
+                // double check
+                if (conContext.isInboundClosed()) {
+                    return;
+                }
+
                 if (!(conContext.inputRecord instanceof SSLSocketInputRecord)) {
                     return;
                 }
@@ -927,25 +1042,32 @@
                             "input stream close depletion failed", ioe);
                     }
                 }
+            } finally {
+                readLock.unlock();
             }
         }
     }
 
     @Override
-    public synchronized OutputStream getOutputStream() throws IOException {
-        if (isClosed()) {
-            throw new SocketException("Socket is closed");
-        }
+    public OutputStream getOutputStream() throws IOException {
+        socketLock.lock();
+        try {
+            if (isClosed()) {
+                throw new SocketException("Socket is closed");
+            }
 
-        if (!isConnected) {
-            throw new SocketException("Socket is not connected");
-        }
+            if (!isConnected) {
+                throw new SocketException("Socket is not connected");
+            }
 
-        if (conContext.isOutboundDone() || isOutputShutdown()) {
-            throw new SocketException("Socket output is already shutdown");
+            if (conContext.isOutboundDone() || isOutputShutdown()) {
+                throw new SocketException("Socket output is already shutdown");
+            }
+
+            return appOutput;
+        } finally {
+            socketLock.unlock();
         }
-
-        return appOutput;
     }
 
 
@@ -1035,44 +1157,74 @@
     }
 
     @Override
-    public synchronized SSLParameters getSSLParameters() {
-        return conContext.sslConfig.getSSLParameters();
-    }
-
-    @Override
-    public synchronized void setSSLParameters(SSLParameters params) {
-        conContext.sslConfig.setSSLParameters(params);
-
-        if (conContext.sslConfig.maximumPacketSize != 0) {
-            conContext.outputRecord.changePacketSize(
-                    conContext.sslConfig.maximumPacketSize);
+    public SSLParameters getSSLParameters() {
+        socketLock.lock();
+        try {
+            return conContext.sslConfig.getSSLParameters();
+        } finally {
+            socketLock.unlock();
         }
     }
 
     @Override
-    public synchronized String getApplicationProtocol() {
-        return conContext.applicationProtocol;
+    public void setSSLParameters(SSLParameters params) {
+        socketLock.lock();
+        try {
+            conContext.sslConfig.setSSLParameters(params);
+
+            if (conContext.sslConfig.maximumPacketSize != 0) {
+                conContext.outputRecord.changePacketSize(
+                        conContext.sslConfig.maximumPacketSize);
+            }
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized String getHandshakeApplicationProtocol() {
-        if (conContext.handshakeContext != null) {
-            return conContext.handshakeContext.applicationProtocol;
+    public String getApplicationProtocol() {
+        socketLock.lock();
+        try {
+            return conContext.applicationProtocol;
+        } finally {
+            socketLock.unlock();
+        }
+    }
+
+    @Override
+    public String getHandshakeApplicationProtocol() {
+        socketLock.lock();
+        try {
+            if (conContext.handshakeContext != null) {
+                return conContext.handshakeContext.applicationProtocol;
+            }
+        } finally {
+            socketLock.unlock();
         }
 
         return null;
     }
 
     @Override
-    public synchronized void setHandshakeApplicationProtocolSelector(
+    public void setHandshakeApplicationProtocolSelector(
             BiFunction<SSLSocket, List<String>, String> selector) {
-        conContext.sslConfig.socketAPSelector = selector;
+        socketLock.lock();
+        try {
+            conContext.sslConfig.socketAPSelector = selector;
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     @Override
-    public synchronized BiFunction<SSLSocket, List<String>, String>
+    public BiFunction<SSLSocket, List<String>, String>
             getHandshakeApplicationProtocolSelector() {
-        return conContext.sslConfig.socketAPSelector;
+        socketLock.lock();
+        try {
+            return conContext.sslConfig.socketAPSelector;
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     /**
@@ -1142,8 +1294,11 @@
 
             try {
                 Plaintext plainText;
-                synchronized (this) {
+                socketLock.lock();
+                try {
                     plainText = decode(buffer);
+                } finally {
+                    socketLock.unlock();
                 }
                 if (plainText.contentType == ContentType.APPLICATION_DATA.id &&
                         buffer.position() > 0) {
@@ -1222,27 +1377,33 @@
      *
      * Called by connect, the layered constructor, and SSLServerSocket.
      */
-    synchronized void doneConnect() throws IOException {
-        // In server mode, it is not necessary to set host and serverNames.
-        // Otherwise, would require a reverse DNS lookup to get the hostname.
-        if (peerHost == null || peerHost.isEmpty()) {
-            boolean useNameService =
-                    trustNameService && conContext.sslConfig.isClientMode;
-            useImplicitHost(useNameService);
-        } else {
-            conContext.sslConfig.serverNames =
-                    Utilities.addToSNIServerNameList(
-                            conContext.sslConfig.serverNames, peerHost);
+    void doneConnect() throws IOException {
+        socketLock.lock();
+        try {
+            // In server mode, it is not necessary to set host and serverNames.
+            // Otherwise, would require a reverse DNS lookup to get
+            // the hostname.
+            if (peerHost == null || peerHost.isEmpty()) {
+                boolean useNameService =
+                        trustNameService && conContext.sslConfig.isClientMode;
+                useImplicitHost(useNameService);
+            } else {
+                conContext.sslConfig.serverNames =
+                        Utilities.addToSNIServerNameList(
+                                conContext.sslConfig.serverNames, peerHost);
+            }
+
+            InputStream sockInput = super.getInputStream();
+            conContext.inputRecord.setReceiverStream(sockInput);
+
+            OutputStream sockOutput = super.getOutputStream();
+            conContext.inputRecord.setDeliverStream(sockOutput);
+            conContext.outputRecord.setDeliverStream(sockOutput);
+
+            this.isConnected = true;
+        } finally {
+            socketLock.unlock();
         }
-
-        InputStream sockInput = super.getInputStream();
-        conContext.inputRecord.setReceiverStream(sockInput);
-
-        OutputStream sockOutput = super.getOutputStream();
-        conContext.inputRecord.setDeliverStream(sockOutput);
-        conContext.outputRecord.setDeliverStream(sockOutput);
-
-        this.isConnected = true;
     }
 
     private void useImplicitHost(boolean useNameService) {
@@ -1288,11 +1449,16 @@
     // Please NOTE that this method MUST be called before calling to
     // SSLSocket.setSSLParameters(). Otherwise, the {@code host} parameter
     // may override SNIHostName in the customized server name indication.
-    public synchronized void setHost(String host) {
-        this.peerHost = host;
-        this.conContext.sslConfig.serverNames =
-                Utilities.addToSNIServerNameList(
-                        conContext.sslConfig.serverNames, host);
+    public void setHost(String host) {
+        socketLock.lock();
+        try {
+            this.peerHost = host;
+            this.conContext.sslConfig.serverNames =
+                    Utilities.addToSNIServerNameList(
+                            conContext.sslConfig.serverNames, host);
+        } finally {
+            socketLock.unlock();
+        }
     }
 
     /**
--- a/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java	Fri Apr 05 11:28:23 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,123 +51,206 @@
     }
 
     @Override
-    synchronized void encodeAlert(
-            byte level, byte description) throws IOException {
-        if (isClosed()) {
-            if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
-                SSLLogger.warning("outbound has closed, ignore outbound " +
-                    "alert message: " + Alert.nameOf(description));
+    void encodeAlert(byte level, byte description) throws IOException {
+        recordLock.lock();
+        try {
+            if (isClosed()) {
+                if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+                    SSLLogger.warning("outbound has closed, ignore outbound " +
+                        "alert message: " + Alert.nameOf(description));
+                }
+                return;
             }
-            return;
-        }
 
-        // use the buf of ByteArrayOutputStream
-        int position = headerSize + writeCipher.getExplicitNonceSize();
-        count = position;
+            // use the buf of ByteArrayOutputStream
+            int position = headerSize + writeCipher.getExplicitNonceSize();
+            count = position;
 
-        write(level);
-        write(description);
-        if (SSLLogger.isOn && SSLLogger.isOn("record")) {
-            SSLLogger.fine("WRITE: " + protocolVersion +
-                    " " + ContentType.ALERT.name +
-                    "(" + Alert.nameOf(description) + ")" +
-                    ", length = " + (count - headerSize));
-        }
+            write(level);
+            write(description);
+            if (SSLLogger.isOn && SSLLogger.isOn("record")) {
+                SSLLogger.fine("WRITE: " + protocolVersion +
+                        " " + ContentType.ALERT.name +
+                        "(" + Alert.nameOf(description) + ")" +
+                        ", length = " + (count - headerSize));
+            }
 
-        // Encrypt the fragment and wrap up a record.
-        encrypt(writeCipher, ContentType.ALERT.id, headerSize);
+            // Encrypt the fragment and wrap up a record.
+            encrypt(writeCipher, ContentType.ALERT.id, headerSize);
 
-        // deliver this message
-        deliverStream.write(buf, 0, count);    // may throw IOException
-        deliverStream.flush();                 // may throw IOException
+            // deliver this message
+            deliverStream.write(buf, 0, count);    // may throw IOException
+            deliverStream.flush();                 // may throw IOException
 
-        if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
-            SSLLogger.fine("Raw write",
-                    (new ByteArrayInputStream(buf, 0, count)));
+            if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
+                SSLLogger.fine("Raw write",
+                        (new ByteArrayInputStream(buf, 0, count)));
+            }
+
+            // reset the internal buffer
+            count = 0;
+        } finally {
+            recordLock.unlock();
         }
-
-        // reset the internal buffer
-        count = 0;
     }
 
     @Override
-    synchronized void encodeHandshake(byte[] source,
+    void encodeHandshake(byte[] source,
             int offset, int length) throws IOException {
-        if (isClosed()) {
-            if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
-                SSLLogger.warning("outbound has closed, ignore outbound " +
-                        "handshake message",
-                        ByteBuffer.wrap(source, offset, length));
+        recordLock.lock();
+        try {
+            if (isClosed()) {
+                if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+                    SSLLogger.warning("outbound has closed, ignore outbound " +
+                            "handshake message",
+                            ByteBuffer.wrap(source, offset, length));
+                }
+                return;
             }
-            return;
-        }
+
+            if (firstMessage) {
+                firstMessage = false;
 
-        if (firstMessage) {
-            firstMessage = false;
-
-            if ((helloVersion == ProtocolVersion.SSL20Hello) &&
-                (source[offset] == SSLHandshake.CLIENT_HELLO.id) &&
+                if ((helloVersion == ProtocolVersion.SSL20Hello) &&
+                    (source[offset] == SSLHandshake.CLIENT_HELLO.id) &&
                                             //  5: recode header size
-                (source[offset + 4 + 2 + 32] == 0)) {
+                    (source[offset + 4 + 2 + 32] == 0)) {
                                             // V3 session ID is empty
                                             //  4: handshake header size
                                             //  2: client_version in ClientHello
                                             // 32: random in ClientHello
 
-                ByteBuffer v2ClientHello = encodeV2ClientHello(
-                        source, (offset + 4), (length - 4));
+                    ByteBuffer v2ClientHello = encodeV2ClientHello(
+                            source, (offset + 4), (length - 4));
+
+                    // array offset is zero
+                    byte[] record = v2ClientHello.array();
+                    int limit = v2ClientHello.limit();
+                    handshakeHash.deliver(record, 2, (limit - 2));
+
+                    if (SSLLogger.isOn && SSLLogger.isOn("record")) {
+                        SSLLogger.fine(
+                                "WRITE: SSLv2 ClientHello message" +
+                                ", length = " + limit);
+                    }
+
+                    // deliver this message
+                    //
+                    // Version 2 ClientHello message should be plaintext.
+                    //
+                    // No max fragment length negotiation.
+                    deliverStream.write(record, 0, limit);
+                    deliverStream.flush();
+
+                    if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
+                        SSLLogger.fine("Raw write",
+                                (new ByteArrayInputStream(record, 0, limit)));
+                    }
 
-                byte[] record = v2ClientHello.array();  // array offset is zero
-                int limit = v2ClientHello.limit();
-                handshakeHash.deliver(record, 2, (limit - 2));
+                    return;
+                }
+            }
+
+            byte handshakeType = source[0];
+            if (handshakeHash.isHashable(handshakeType)) {
+                handshakeHash.deliver(source, offset, length);
+            }
+
+            int fragLimit = getFragLimit();
+            int position = headerSize + writeCipher.getExplicitNonceSize();
+            if (count == 0) {
+                count = position;
+            }
+
+            if ((count - position) < (fragLimit - length)) {
+                write(source, offset, length);
+                return;
+            }
+
+            for (int limit = (offset + length); offset < limit;) {
+
+                int remains = (limit - offset) + (count - position);
+                int fragLen = Math.min(fragLimit, remains);
+
+                // use the buf of ByteArrayOutputStream
+                write(source, offset, fragLen);
+                if (remains < fragLimit) {
+                    return;
+                }
 
                 if (SSLLogger.isOn && SSLLogger.isOn("record")) {
                     SSLLogger.fine(
-                            "WRITE: SSLv2 ClientHello message" +
-                            ", length = " + limit);
+                            "WRITE: " + protocolVersion +
+                            " " + ContentType.HANDSHAKE.name +
+                            ", length = " + (count - headerSize));
                 }
 
+                // Encrypt the fragment and wrap up a record.
+                encrypt(writeCipher, ContentType.HANDSHAKE.id, headerSize);
+
                 // deliver this message
-                //
-                // Version 2 ClientHello message should be plaintext.
-                //
-                // No max fragment length negotiation.
-                deliverStream.write(record, 0, limit);
-                deliverStream.flush();
+                deliverStream.write(buf, 0, count);    // may throw IOException
+                deliverStream.flush();                 // may throw IOException
 
                 if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
                     SSLLogger.fine("Raw write",
-                            (new ByteArrayInputStream(record, 0, limit)));
+                            (new ByteArrayInputStream(buf, 0, count)));
                 }
 
+                // reset the offset
+                offset += fragLen;
+
+                // reset the internal buffer
+                count = position;
+            }
+        } finally {
+            recordLock.unlock();
+        }
+    }
+
+    @Override
+    void encodeChangeCipherSpec() throws IOException {
+        recordLock.lock();
+        try {
+            if (isClosed()) {
+                if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+                    SSLLogger.warning("outbound has closed, ignore outbound " +
+                        "change_cipher_spec message");
+                }
                 return;
             }
-        }
-
-        byte handshakeType = source[0];
-        if (handshakeHash.isHashable(handshakeType)) {
-            handshakeHash.deliver(source, offset, length);
-        }
-
-        int fragLimit = getFragLimit();
-        int position = headerSize + writeCipher.getExplicitNonceSize();
-        if (count == 0) {
-            count = position;
-        }
-
-        if ((count - position) < (fragLimit - length)) {
-            write(source, offset, length);
-            return;
-        }
-
-        for (int limit = (offset + length); offset < limit;) {
-
-            int remains = (limit - offset) + (count - position);
-            int fragLen = Math.min(fragLimit, remains);
 
             // use the buf of ByteArrayOutputStream
-            write(source, offset, fragLen);
-            if (remains < fragLimit) {
+            int position = headerSize + writeCipher.getExplicitNonceSize();
+            count = position;
+
+            write((byte)1);         // byte 1: change_cipher_spec(
+
+            // Encrypt the fragment and wrap up a record.
+            encrypt(writeCipher, ContentType.CHANGE_CIPHER_SPEC.id, headerSize);
+
+            // deliver this message
+            deliverStream.write(buf, 0, count);        // may throw IOException
+            // deliverStream.flush();                  // flush in Finished
+
+            if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
+                SSLLogger.fine("Raw write",
+                        (new ByteArrayInputStream(buf, 0, count)));
+            }
+
+            // reset the internal buffer
+            count = 0;
+        } finally {
+            recordLock.unlock();
+        }
+    }
+
+    @Override
+    public void flush() throws IOException {
+        recordLock.lock();
+        try {
+            int position = headerSize + writeCipher.getExplicitNonceSize();
+            if (count <= position) {
                 return;
             }
 
@@ -190,155 +273,103 @@
                         (new ByteArrayInputStream(buf, 0, count)));
             }
 
-            // reset the offset
-            offset += fragLen;
-
             // reset the internal buffer
-            count = position;
+            count = 0;      // DON'T use position
+        } finally {
+            recordLock.unlock();
         }
     }
 
     @Override
-    synchronized void encodeChangeCipherSpec() throws IOException {
-        if (isClosed()) {
-            if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
-                SSLLogger.warning("outbound has closed, ignore outbound " +
-                    "change_cipher_spec message");
+    void deliver(byte[] source, int offset, int length) throws IOException {
+        recordLock.lock();
+        try {
+            if (isClosed()) {
+                throw new SocketException(
+                        "Connection or outbound has been closed");
             }
-            return;
-        }
-
-        // use the buf of ByteArrayOutputStream
-        int position = headerSize + writeCipher.getExplicitNonceSize();
-        count = position;
-
-        write((byte)1);         // byte 1: change_cipher_spec(
-
-        // Encrypt the fragment and wrap up a record.
-        encrypt(writeCipher, ContentType.CHANGE_CIPHER_SPEC.id, headerSize);
-
-        // deliver this message
-        deliverStream.write(buf, 0, count);        // may throw IOException
-        // deliverStream.flush();                  // flush in Finished
-
-        if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
-            SSLLogger.fine("Raw write",
-                    (new ByteArrayInputStream(buf, 0, count)));
-        }
-
-        // reset the internal buffer
-        count = 0;
-    }
 
-    @Override
-    public synchronized void flush() throws IOException {
-        int position = headerSize + writeCipher.getExplicitNonceSize();
-        if (count <= position) {
-            return;
-        }
-
-        if (SSLLogger.isOn && SSLLogger.isOn("record")) {
-            SSLLogger.fine(
-                    "WRITE: " + protocolVersion +
-                    " " + ContentType.HANDSHAKE.name +
-                    ", length = " + (count - headerSize));
-        }
-
-        // Encrypt the fragment and wrap up a record.
-        encrypt(writeCipher, ContentType.HANDSHAKE.id, headerSize);
-
-        // deliver this message
-        deliverStream.write(buf, 0, count);    // may throw IOException
-        deliverStream.flush();                 // may throw IOException
+            if (writeCipher.authenticator.seqNumOverflow()) {
+                if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+                    SSLLogger.fine(
+                        "sequence number extremely close to overflow " +
+                        "(2^64-1 packets). Closing connection.");
+                }
 
-        if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
-            SSLLogger.fine("Raw write",
-                    (new ByteArrayInputStream(buf, 0, count)));
-        }
-
-        // reset the internal buffer
-        count = 0;      // DON'T use position
-    }
-
-    @Override
-    synchronized void deliver(
-            byte[] source, int offset, int length) throws IOException {
-        if (isClosed()) {
-            throw new SocketException("Connection or outbound has been closed");
-        }
-
-        if (writeCipher.authenticator.seqNumOverflow()) {
-            if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
-                SSLLogger.fine(
-                    "sequence number extremely close to overflow " +
-                    "(2^64-1 packets). Closing connection.");
+                throw new SSLHandshakeException("sequence number overflow");
             }
 
-            throw new SSLHandshakeException("sequence number overflow");
-        }
+            boolean isFirstRecordOfThePayload = true;
+            for (int limit = (offset + length); offset < limit;) {
+                int fragLen;
+                if (packetSize > 0) {
+                    fragLen = Math.min(maxRecordSize, packetSize);
+                    fragLen = writeCipher.calculateFragmentSize(
+                            fragLen, headerSize);
 
-        boolean isFirstRecordOfThePayload = true;
-        for (int limit = (offset + length); offset < limit;) {
-            int fragLen;
-            if (packetSize > 0) {
-                fragLen = Math.min(maxRecordSize, packetSize);
-                fragLen =
-                        writeCipher.calculateFragmentSize(fragLen, headerSize);
+                    fragLen = Math.min(fragLen, Record.maxDataSize);
+                } else {
+                    fragLen = Record.maxDataSize;
+                }
 
-                fragLen = Math.min(fragLen, Record.maxDataSize);
-            } else {
-                fragLen = Record.maxDataSize;
-            }
+                if (fragmentSize > 0) {
+                    fragLen = Math.min(fragLen, fragmentSize);
+                }
 
-            if (fragmentSize > 0) {
-                fragLen = Math.min(fragLen, fragmentSize);
-            }
+                if (isFirstRecordOfThePayload && needToSplitPayload()) {
+                    fragLen = 1;
+                    isFirstRecordOfThePayload = false;
+                } else {
+                    fragLen = Math.min(fragLen, (limit - offset));
+                }
 
-            if (isFirstRecordOfThePayload && needToSplitPayload()) {
-                fragLen = 1;
-                isFirstRecordOfThePayload = false;
-            } else {
-                fragLen = Math.min(fragLen, (limit - offset));
-            }
+                // use the buf of ByteArrayOutputStream
+                int position = headerSize + writeCipher.getExplicitNonceSize();
+                count = position;
+                write(source, offset, fragLen);
 
-            // use the buf of ByteArrayOutputStream
-            int position = headerSize + writeCipher.getExplicitNonceSize();
-            count = position;
-            write(source, offset, fragLen);
+                if (SSLLogger.isOn && SSLLogger.isOn("record")) {
+                    SSLLogger.fine(
+                            "WRITE: " + protocolVersion +
+                            " " + ContentType.APPLICATION_DATA.name +
+                            ", length = " + (count - position));
+                }
 
-            if (SSLLogger.isOn && SSLLogger.isOn("record")) {
-                SSLLogger.fine(
-                        "WRITE: " + protocolVersion +
-                        " " + ContentType.APPLICATION_DATA.name +
-                        ", length = " + (count - position));
-            }
+                // Encrypt the fragment and wrap up a record.
+                encrypt(writeCipher,
+                        ContentType.APPLICATION_DATA.id, headerSize);
 
-            // Encrypt the fragment and wrap up a record.
-            encrypt(writeCipher, ContentType.APPLICATION_DATA.id, headerSize);
+                // deliver this message
+                deliverStream.write(buf, 0, count);    // may throw IOException
+                deliverStream.flush();                 // may throw IOException
 
-            // deliver this message
-            deliverStream.write(buf, 0, count);    // may throw IOException
-            deliverStream.flush();                 // may throw IOException
+                if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
+                    SSLLogger.fine("Raw write",
+                            (new ByteArrayInputStream(buf, 0, count)));
+                }
 
-            if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
-                SSLLogger.fine("Raw write",
-                        (new ByteArrayInputStream(buf, 0, count)));
-            }
+                // reset the internal buffer
+                count = 0;
 
-            // reset the internal buffer
-            count = 0;
+                if (isFirstAppOutputRecord) {
+                    isFirstAppOutputRecord = false;
+                }
 
-            if (isFirstAppOutputRecord) {
-                isFirstAppOutputRecord = false;
+                offset += fragLen;
             }
-
-            offset += fragLen;
+        } finally {
+            recordLock.unlock();
         }
     }
 
     @Override
-    synchronized void setDeliverStream(OutputStream outputStream) {
-        this.deliverStream = outputStream;
+    void setDeliverStream(OutputStream outputStream) {
+        recordLock.lock();
+        try {
+            this.deliverStream = outputStream;
+        } finally {
+            recordLock.unlock();
+        }
     }
 
     /*
--- a/src/java.base/share/classes/sun/security/ssl/SunX509KeyManagerImpl.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/SunX509KeyManagerImpl.java	Fri Apr 05 11:28:23 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -102,25 +102,21 @@
      * Basic container for credentials implemented as an inner class.
      */
     private static class X509Credentials {
-        PrivateKey privateKey;
-        X509Certificate[] certificates;
-        private Set<X500Principal> issuerX500Principals;
+        final PrivateKey privateKey;
+        final X509Certificate[] certificates;
+        private final Set<X500Principal> issuerX500Principals;
 
         X509Credentials(PrivateKey privateKey, X509Certificate[] certificates) {
             // assert privateKey and certificates != null
             this.privateKey = privateKey;
             this.certificates = certificates;
+            this.issuerX500Principals = new HashSet<>(certificates.length);
+            for (X509Certificate certificate : certificates) {
+                issuerX500Principals.add(certificate.getIssuerX500Principal());
+            }
         }
 
-        synchronized Set<X500Principal> getIssuerX500Principals() {
-            // lazy initialization
-            if (issuerX500Principals == null) {
-                issuerX500Principals = new HashSet<X500Principal>();
-                for (int i = 0; i < certificates.length; i++) {
-                    issuerX500Principals.add(
-                                certificates[i].getIssuerX500Principal());
-                }
-            }
+        Set<X500Principal> getIssuerX500Principals() {
             return issuerX500Principals;
         }
     }
--- a/src/java.base/share/classes/sun/security/ssl/TransportContext.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/TransportContext.java	Fri Apr 05 11:28:23 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -496,13 +496,16 @@
             }
 
             if (needCloseNotify) {
-                synchronized (outputRecord) {
+                outputRecord.recordLock.lock();
+                try {
                     try {
                         // send a close_notify alert
                         warning(Alert.CLOSE_NOTIFY);
                     } finally {
                         outputRecord.close();
                     }
+                } finally {
+                    outputRecord.recordLock.unlock();
                 }
             }
         }
@@ -541,7 +544,8 @@
 
         // Need a lock here so that the user_canceled alert and the
         // close_notify alert can be delivered together.
-        synchronized (outputRecord) {
+        outputRecord.recordLock.lock();
+        try {
             try {
                 // send a user_canceled alert if needed.
                 if (useUserCanceled) {
@@ -553,6 +557,8 @@
             } finally {
                 outputRecord.close();
             }
+        } finally {
+            outputRecord.recordLock.unlock();
         }
     }
 
--- a/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java	Fri Apr 05 11:28:23 2019 -0700
@@ -30,6 +30,7 @@
 import java.security.*;
 import java.security.cert.*;
 import java.util.*;
+import java.util.concurrent.locks.ReentrantLock;
 import sun.security.action.*;
 import sun.security.validator.TrustStoreUtil;
 
@@ -244,6 +245,8 @@
         // objects can be atomically cleared, and reloaded if needed.
         private WeakReference<Set<X509Certificate>> csRef;
 
+        private final ReentrantLock tamLock = new ReentrantLock();
+
         private TrustAnchorManager() {
             this.descriptor = null;
             this.ksRef = new WeakReference<>(null);
@@ -255,7 +258,7 @@
          *
          * @return null if the underlying KeyStore is not available.
          */
-        synchronized KeyStore getKeyStore(
+        KeyStore getKeyStore(
                 TrustStoreDescriptor descriptor) throws Exception {
 
             TrustStoreDescriptor temporaryDesc = this.descriptor;
@@ -264,15 +267,26 @@
                 return ks;
             }
 
-            // Reload a new key store.
-            if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
-                SSLLogger.fine("Reload the trust store");
+            tamLock.lock();
+            try {
+                // double check
+                ks = ksRef.get();
+                if ((ks != null) && descriptor.equals(temporaryDesc)) {
+                    return ks;
+                }
+
+                // Reload a new key store.
+                if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
+                    SSLLogger.fine("Reload the trust store");
+                }
+
+                ks = loadKeyStore(descriptor);
+                this.descriptor = descriptor;
+                this.ksRef = new WeakReference<>(ks);
+            } finally {
+                tamLock.unlock();
             }
 
-            ks = loadKeyStore(descriptor);
-            this.descriptor = descriptor;
-            this.ksRef = new WeakReference<>(ks);
-
             return ks;
         }
 
@@ -282,51 +296,62 @@
          *
          * @return empty collection if the underlying KeyStore is not available.
          */
-        synchronized Set<X509Certificate> getTrustedCerts(
+        Set<X509Certificate> getTrustedCerts(
                 TrustStoreDescriptor descriptor) throws Exception {
 
             KeyStore ks = null;
             TrustStoreDescriptor temporaryDesc = this.descriptor;
             Set<X509Certificate> certs = csRef.get();
-            if (certs != null) {
-                if (descriptor.equals(temporaryDesc)) {
-                    return certs;
-                } else {
-                    // Use the new descriptor.
-                    this.descriptor = descriptor;
-                }
-            } else {
-                // Try to use the cached store at first.
-                if (descriptor.equals(temporaryDesc)) {
-                    ks = ksRef.get();
-                } else {
-                    // Use the new descriptor.
-                    this.descriptor = descriptor;
-                }
+            if ((certs != null) && descriptor.equals(temporaryDesc)) {
+                return certs;
             }
 
-            // Reload the trust store if needed.
-            if (ks == null) {
-                if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
-                    SSLLogger.fine("Reload the trust store");
+            tamLock.lock();
+            try {
+                // double check
+                temporaryDesc = this.descriptor;
+                certs = csRef.get();
+                if (certs != null) {
+                    if (descriptor.equals(temporaryDesc)) {
+                        return certs;
+                    } else {
+                        // Use the new descriptor.
+                        this.descriptor = descriptor;
+                    }
+                } else {
+                    // Try to use the cached store at first.
+                    if (descriptor.equals(temporaryDesc)) {
+                        ks = ksRef.get();
+                    } else {
+                        // Use the new descriptor.
+                        this.descriptor = descriptor;
+                    }
                 }
-                ks = loadKeyStore(descriptor);
-            }
 
-            // Reload trust certs from the key store.
-            if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
-                SSLLogger.fine("Reload trust certs");
-            }
+                // Reload the trust store if needed.
+                if (ks == null) {
+                    if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
+                        SSLLogger.fine("Reload the trust store");
+                    }
+                    ks = loadKeyStore(descriptor);
+                    this.ksRef = new WeakReference<>(ks);
+                }
 
-            certs = loadTrustedCerts(ks);
-            if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
-                SSLLogger.fine("Reloaded " + certs.size() + " trust certs");
+                // Reload trust certs from the key store.
+                if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
+                    SSLLogger.fine("Reload trust certs");
+                }
+
+                certs = loadTrustedCerts(ks);
+                if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
+                    SSLLogger.fine("Reloaded " + certs.size() + " trust certs");
+                }
+
+                this.csRef = new WeakReference<>(certs);
+            } finally {
+                tamLock.unlock();
             }
 
-            // Note that as ks is a local variable, it is not
-            // necessary to add it to the ksRef weak reference.
-            this.csRef = new WeakReference<>(certs);
-
             return certs;
         }
 
--- a/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java	Fri Apr 05 11:17:09 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java	Fri Apr 05 11:28:23 2019 -0700
@@ -29,6 +29,7 @@
 import java.security.*;
 import java.security.cert.*;
 import java.util.*;
+import java.util.concurrent.locks.ReentrantLock;
 import javax.net.ssl.*;
 import sun.security.util.AnchorCertificates;
 import sun.security.util.HostnameChecker;
@@ -63,6 +64,8 @@
     // the different extension checks. They are initialized lazily on demand.
     private volatile Validator clientValidator, serverValidator;
 
+    private final ReentrantLock validatorLock = new ReentrantLock();
+
     X509TrustManagerImpl(String validatorType,
             Collection<X509Certificate> trustedCerts) {
 
@@ -157,12 +160,15 @@
         if (isClient) {
             v = clientValidator;
             if (v == null) {
-                synchronized (this) {
+                validatorLock.lock();
+                try {
                     v = clientValidator;
                     if (v == null) {
                         v = getValidator(Validator.VAR_TLS_CLIENT);
                         clientValidator = v;
                     }
+                } finally {
+                    validatorLock.unlock();
                 }
             }
         } else {
@@ -170,12 +176,15 @@
             // (guaranteed under the new Tiger memory model)
             v = serverValidator;
             if (v == null) {
-                synchronized (this) {
+                validatorLock.lock();
+                try {
                     v = serverValidator;
                     if (v == null) {
                         v = getValidator(Validator.VAR_TLS_SERVER);
                         serverValidator = v;
                     }
+                } finally {
+                    validatorLock.unlock();
                 }
             }
         }