...
Code Block |
---|
|
public final class Lazy {
private static int number;
private static Connection conn;
static {
Thread t = new Thread(new Runnable() {
public void run() {
// Initialize, a database connection
try {
conn = DriverManager.getConnection("connectionstring");
} catch (SQLException e) {
conn = null;
}
}
});
t.start();
try {
t.join();
} catch(InterruptedException ie) {
throw new AssertionError(ie);
}
// Other initialization
number = 42;
}
public static Connection getConnection() {
if(conn == null) {
throw new IllegalStateException("Connection not initialized");
}
return conn;
}
public static void main(String[] args) {
// System.out.println(number...
Connection connection = Lazy.getConnection();
}
}
|
The code in the static
block is responsible for initialization, and starts a background thread. The background thread attempts to initialize a database connection and also assigns to the field number
but needs to wait until initialization of all members of the Lazy
class has finished.
...
Code Block |
---|
|
public final class Lazy {
private static int number;
private static Connection conn;
static {
// Initialize, a database connection
try {
conn = DriverManager.getConnection("connectionstring");
} catch (SQLException e) {
conn = null;
}
// Other initialization
number = 42;
}
// ...
}
|
Compliant Solution (ThreadLocal
)
This compliant solution uses a ThreadLocal
object to initialize a the database connection and sets flag
to true
depending on whether the initialization succeeds. The number
field is initialized independently in a static initializer.
Code Block |
---|
|
public final class Lazy {
private static boolean flag;
private static int number;
static {
number = 42;
}
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) {
flag = false;
return null;
}
}
};
public static Connection getConnection() {
Connection connection return= connectionHolder.get();
if(connection == null) {
throw new IllegalStateException("Connection not initialized");
}
return connection;
}
public static void main(String[] args) {
// ...
Connection conn = getConnection();
System.out.println(flag);
}
}
|
It is also safe to set other shared class variables from the initialValue()
method. Consequently, each thread will see a consistent value of the flag
field.
Exceptions
Wiki Markup |
---|
*CON03:EX1*: The {{ObjectPreserver}} class (based on \[[Patterns 02|AA. Java References#Patterns 02]\]) is shown below: This class provides a mechanism for storing object references, which prevents an object from being garbage-collected, even if the remaining program no longer maintains a reference to the object. |
...