...
Wiki Markup |
---|
The code in the {{static}} block is responsible for initialization, and starts a background thread. The background thread attempts to assign to the {{flag}} but needs to wait before initialization of the {{Lazy}} class has finished. Remember 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 info). Consequently the background thread must wait for the foreground thread to finish initialization before it may 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]\] |
flag
is not required to be volatile
because the initialization is being carried out in a static initializer and is guaranteed to finish before the object becomes usable. Similar to this noncompliant code example, threads should not be started from constructors. See CON14-J. Do not let the "this" reference escape during object construction for more information.
...
Code Block | ||
---|---|---|
| ||
public class Lazy { private static boolean flag = false; private static final ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() { public Connection initialValue() { try { Connection conn = DriverManager.getConnection("connectionstring"); flag = true; return conn; } catch (SQLException e) { return null; } } } }; public static Connection getConnection() { return connectionHolder.get(); } public static void main(String[] args) { Connection conn = getConnection(); System.out.println(flag); } } |
...