...
In this noncompliant code example, the static initializer started starts a background thread as part of class initialization. The background thread attempted attempts to initialize a database connection but should have waited wait until all members of the ConnectionFactory class, including dbConnection, were are initialized.
| Code Block | ||
|---|---|---|
| ||
public final class ConnectionFactory {
private static Connection dbConnection;
// Other fields ...
static {
Thread dbInitializerThread = new Thread(new Runnable() {
@Override public void run() {
// Initialize the database connection
try {
dbConnection = DriverManager.getConnection("connection string");
} catch (SQLException e) {
dbConnection = null;
}
}
});
// Other initialization, for example, start other threads
dbInitializerThread.start();
try {
dbInitializerThread.join();
} catch (InterruptedException ie) {
throw new AssertionError(ie);
}
}
public static Connection getConnection() {
if (dbConnection == null) {
throw new IllegalStateException("Error initializing connection");
}
return dbConnection;
}
public static void main(String[] args) {
// ...
Connection connection = getConnection();
}
}
|
...
| Code Block | ||
|---|---|---|
| ||
public final class ConnectionFactory {
private static final ThreadLocal<Connection> connectionHolder
= new ThreadLocal<Connection>() {
@Override public Connection initialValue() {
try {
Connection dbConnection =
DriverManager.getConnection("connection string");
return dbConnection;
} catch (SQLException e) {
return null;
}
}
};
// Other fields ...
static {
// Other initialization (do not start any threads)
}
public static Connection getConnection() {
Connection connection = connectionHolder.get();
if (connection == null) {
throw new IllegalStateException("Error initializing connection");
}
return connection;
}
public static void main(String[] args) {
// ...
Connection connection = getConnection();
}
}
|
The static initializer can be used to initialize any other shared class fieldsfield. Alternatively, the fields can be initialized from the initialValue() method.
...
| Wiki Markup |
|---|
<ac:structured-macro ac:name="anchor" ac:schema-version="1" ac:macro-id="d8f50820b6c95c5b-b1c4159d-4380478d-8ae181fc-890a8a6f0de8706fa2d26e7b"><ac:parameter ac:name="">CON20-EX1</ac:parameter></ac:structured-macro> *TSM02-EX0:* Programs are permitted to start a background thread (or threads) during class initialization, provided the thread cannot access any fields. For example, the following {{ObjectPreserver}} class (based on \[[Grand 2002|AA. Bibliography#Grand 02]\]) that follows provides a mechanism for storing object references, which prevents an object from being garbage-collected even when the object is never again dereferenced. |
...
Starting and using background threads during class initialization can result in deadlock conditions.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
TSM02-J | low | probable | high | P2 | L3 |
...
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="969d72a1f9175351-f906d577-4a84412e-9667a85e-05e69297a9fe838246e14dc2"><ac:plain-text-body><![CDATA[ | [[Bloch 2005b | AA. Bibliography#Bloch 05b]] | 8, Lazy Initialization | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="716f0439cee03650-36446cb6-47f64432-aea297e6-7f107e51b104d7d2db83c134"><ac:plain-text-body><![CDATA[ | [[Grand 2002 | AA. Bibliography#Grand 02]] | Chapter 5, Creational Patterns, Singleton | ]]></ac:plain-text-body></ac:structured-macro> |
...