关于 HandshakeCompletedNotify-Thread 线程
最近诊断一个线程泄漏问题的时候, 发现大量的 HandshakeCompletedNotify-Thread 线程, 观察它的代码栈, 发现源自于 JDK 代码 sun.security.ssl.TransportContext.finishHandshake.
每次 SSL 连接建立都创建一个新的线程去做通知, 显然是有性能问题. 可是这个问题尚没有修复, 看上去为了兼容老的 API没人想修复: https://bugs.openjdk.java.net/browse/JDK-8246039
所以尽量连接重用, 减少性能开销.
创建线程栈:
HandshakeCompletedNotify-Thread
java.lang.Thread.start(Thread.java)
sun.security.ssl.TransportContext.finishHandshake(TransportContext.java:620)
sun.security.ssl.Finished$T12FinishedConsumer.onConsumeFinished(Finished.java:546)
sun.security.ssl.Finished$T12FinishedConsumer.consume(Finished.java:515)
sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:377)
sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:444)
sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:422)
sun.security.ssl.TransportContext.dispatch(TransportContext.java:182)
sun.security.ssl.SSLTransport.decode(SSLTransport.java:156)
sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1409)
sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1315)
sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:439)
sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:410)
sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:197)
sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1570)
sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1498)
sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:268)
这段代码:
HandshakeStatus finishHandshake() {
if (protocolVersion.useTLS13PlusSpec()) {
outputRecord.tc = this;
inputRecord.tc = this;
cipherSuite = handshakeContext.negotiatedCipherSuite;
inputRecord.readCipher.baseSecret =
handshakeContext.baseReadSecret;
outputRecord.writeCipher.baseSecret =
handshakeContext.baseWriteSecret;
}
handshakeContext = null;
outputRecord.handshakeHash.finish();
inputRecord.finishHandshake();
outputRecord.finishHandshake();
isNegotiated = true;
// Tell folk about handshake completion, but do it in a separate thread.
if (transport instanceof SSLSocket &&
sslConfig.handshakeListeners != null &&
!sslConfig.handshakeListeners.isEmpty()) {
HandshakeCompletedEvent hce =
new HandshakeCompletedEvent((SSLSocket)transport, conSession);
Thread thread = new Thread(
null,
new NotifyHandshake(sslConfig.handshakeListeners, hce),
"HandshakeCompletedNotify-Thread",
0,
false);
thread.start();
}
return HandshakeStatus.FINISHED;
}