...
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="35c69f046504ce3d-65fa511f-4c624d1e-a1e5a878-dc15b2c4674e3c7b00eddde6"><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="dfc7c2ea17e1f6e8-9d098a64-40e54fb7-944897d7-1e5f84c8038a20b2028a61b0"><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="abb447658e3474a6-046f448d-484540d7-bb4482d6-3aeb4db1749b86f6cd1d2298"><ac:plain-text-body><![CDATA[ | [[Grand 2002 | AA. Bibliography#Grand 02]] | Chapter 5, Creational Patterns, Singleton | ]]></ac:plain-text-body></ac:structured-macro> |
...