为什么 jdbc DriverManager getConnection() 需要同步(DriverManager.class)?
Why does jdbc DriverManager getConnection() need synchronized(DriverManager.class)?
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
synchronized(DriverManager.class) {
// synchronize loading of the correct classloader.
if (callerCL == null) {
callerCL = Thread.currentThread().getContextClassLoader();
}
}
看不懂评论,什么时候会加载不正确的类加载器?
它似乎没有任何作用,这个 synchronized
块在后来的 Java 版本中被删除了。它存在于 Java 8 更新 275 中,但不存在于 Java 11.0.9 中(我的猜测是它在 Java 9 中被删除)。
对我来说,它看起来像是初始化字段而不是局部变量的代码的遗留物,或者它可能用于解决其他并发问题。在 Java 8 中,一些(静态的)DriverManager
方法(registerDriver
和 deregisterDriver
)被定义为 sychronized
,因此这可能有助于建立这些方法和 getConnection
方法之间的先行关系。但是,由于驱动程序注册存储在 CopyOnWriteArrayList
中,因此没有必要建立这种 happens-before 关系;然而,在较旧的 Java 版本中,这可能是一个普通的 ArrayList
,因此它可能需要 happens-before.
但是,我不想对旧的 Java 版本进行代码考古来证实这些理论中的任何一个。
所以,简而言之:它是不必要的,在后来的 Java 版本中被删除了。
Java 8个片段:
// Worker method called by the public getConnection() methods.
private static Connection getConnection(
String url, java.util.Properties info, Class<?> caller) throws SQLException {
/*
* When callerCl is null, we should check the application's
* (which is invoking this class indirectly)
* classloader, so that the JDBC driver class outside rt.jar
* can be loaded from here.
*/
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
synchronized(DriverManager.class) {
// synchronize loading of the correct classloader.
if (callerCL == null) {
callerCL = Thread.currentThread().getContextClassLoader();
}
}
if(url == null) {
throw new SQLException("The url cannot be null", "08001");
}
Java 11 个片段
// Worker method called by the public getConnection() methods.
private static Connection getConnection(
String url, java.util.Properties info, Class<?> caller) throws SQLException {
/*
* When callerCl is null, we should check the application's
* (which is invoking this class indirectly)
* classloader, so that the JDBC driver class outside rt.jar
* can be loaded from here.
*/
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
if (callerCL == null || callerCL == ClassLoader.getPlatformClassLoader()) {
callerCL = Thread.currentThread().getContextClassLoader();
}
if (url == null) {
throw new SQLException("The url cannot be null", "08001");
}
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
synchronized(DriverManager.class) {
// synchronize loading of the correct classloader.
if (callerCL == null) {
callerCL = Thread.currentThread().getContextClassLoader();
}
}
看不懂评论,什么时候会加载不正确的类加载器?
它似乎没有任何作用,这个 synchronized
块在后来的 Java 版本中被删除了。它存在于 Java 8 更新 275 中,但不存在于 Java 11.0.9 中(我的猜测是它在 Java 9 中被删除)。
对我来说,它看起来像是初始化字段而不是局部变量的代码的遗留物,或者它可能用于解决其他并发问题。在 Java 8 中,一些(静态的)DriverManager
方法(registerDriver
和 deregisterDriver
)被定义为 sychronized
,因此这可能有助于建立这些方法和 getConnection
方法之间的先行关系。但是,由于驱动程序注册存储在 CopyOnWriteArrayList
中,因此没有必要建立这种 happens-before 关系;然而,在较旧的 Java 版本中,这可能是一个普通的 ArrayList
,因此它可能需要 happens-before.
但是,我不想对旧的 Java 版本进行代码考古来证实这些理论中的任何一个。
所以,简而言之:它是不必要的,在后来的 Java 版本中被删除了。
Java 8个片段:
// Worker method called by the public getConnection() methods.
private static Connection getConnection(
String url, java.util.Properties info, Class<?> caller) throws SQLException {
/*
* When callerCl is null, we should check the application's
* (which is invoking this class indirectly)
* classloader, so that the JDBC driver class outside rt.jar
* can be loaded from here.
*/
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
synchronized(DriverManager.class) {
// synchronize loading of the correct classloader.
if (callerCL == null) {
callerCL = Thread.currentThread().getContextClassLoader();
}
}
if(url == null) {
throw new SQLException("The url cannot be null", "08001");
}
Java 11 个片段
// Worker method called by the public getConnection() methods.
private static Connection getConnection(
String url, java.util.Properties info, Class<?> caller) throws SQLException {
/*
* When callerCl is null, we should check the application's
* (which is invoking this class indirectly)
* classloader, so that the JDBC driver class outside rt.jar
* can be loaded from here.
*/
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
if (callerCL == null || callerCL == ClassLoader.getPlatformClassLoader()) {
callerCL = Thread.currentThread().getContextClassLoader();
}
if (url == null) {
throw new SQLException("The url cannot be null", "08001");
}