...
Code Block |
---|
|
public class Lazy {
private static volatile boolean initializedflag = false;
static {
Thread t = new Thread(new Runnable() {
public void run() {
// Initialize, for example, a database connection
initializedflag = true;
}
);
t.start();
try {
t.join();
} catch(InterruptedException ie) {
throw new AssertionError(ie);
}
// Other initialization
}
public static void main(String[] args) {
System.out.println(initializedflag);
}
}
|
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 {{initializedflag}} field but hasneeds to wait before initialization of the {{Lazy}} class has finished. 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]\] |
The field 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.
Compliant Solution (static
initializer)
This compliant solution also uses a static
initializer but does not spawn a background thread during class initialization and uses a static
initializerfrom it.
Code Block |
---|
|
public class Lazy {
private static boolean initializedflag = false;
static {
// Initialize, for example, a database connection
initializedflag = true;
}
public static void main(String[] args) {
System.out.println(initializedflag);
}
}
|
Compliant Solution (ThreadLocal
)
This compliant solution uses a ThreadLocal
object to initialize a database connection and sets the initialized
flag
to true
depending on whether the initialization succeeds.
Code Block |
---|
|
public class Lazy {
private static volatile boolean initializedflag = false;
private static final ThreadLocal<Connection> connectionHolder
= new ThreadLocal<Connection>() {
public Connection initialValue() {
try {
Connection conn = DriverManager.getConnection("connectionstring");
initializedflag = 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(initializedflag);
}
}
|
Risk Assessment
Starting and using background threads during class initialization can result in deadlock conditions.
...