...
This noncompliant code example begins initializing the class Lazy
. The code in the static
block is responsible for initialization, and starts a background thread. The background thread attempts to initialize a database connection but needs to wait until initialization of all members of the Lazy
class, including dbConnection
, has finished.
Code Block | ||
---|---|---|
| ||
public final class Lazy { private static Connection dbConnection; static { Thread dbInitializerThread = new Thread(new Runnable() { public void run() { // Initialize the database connection try { dbConnection = DriverManager.getConnection("connectionstring"); } catch (SQLException e) { dbConnection = null; } } }); dbInitializerThread.start(); try { dbInitializerThread.join(); } catch(InterruptedException ie) { throw new AssertionError(ie); } // Other initialization } public static Connection getConnection() { if(dbConnection == null) { throw new IllegalStateException("Error initializing connection"); } return dbConnection; } public static void main(String[] args) { // ... Connection connection = Lazy.getConnection(); } } |
...
Wiki Markup |
---|
Recall that statically-initialized fields are guaranteed to be fully constructed before becoming visible to other threads (see [CON26-J. Do not publish partially initialized objects] for more information). Consequently, the background thread must wait for the foreground thread to finish initialization before it can proceed. However, the {{Lazy}} class's main thread invokes the {{join()}} method which waits for the background thread to finish. This interdependency causes a class initialization cycle that results in a deadlock situation. \[[Bloch 05b|AA. Java References#Bloch 05b]\] |
...