Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
bgColor#FFcccc
public final class ConnectionFactory {
  private static Connection dbConnection;
  // Other fields ...
	  
  static {
    Thread dbInitializerThread = new Thread(new Runnable() {
      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
bgColor#ccccff
public final class ConnectionFactory {
  private static final ThreadLocal<Connection> connectionHolder
    = new ThreadLocal<Connection>() {
      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();
  }
}

...

Wiki Markup
<ac:structured-macro ac:name="anchor" ac:schema-version="1" ac:macro-id="c26c918c365aaefa-34455134-44de4f83-a20390f4-e7f2ce4d8536188dd5e35ec3"><ac:parameter ac:name="">CON03-EX1</ac:parameter></ac:structured-macro>
*CON03-EX1:* It is permissible to start a background thread during class initialization provided the thread does not access any fields. For example, the {{ObjectPreserver}} class (based on \[[Patterns 02|AA. Java References#Patterns 02]\]) shown below provides a mechanism for storing object references, which prevents an object from being garbage-collected, even if the object is not dereferenced in the future.

Code Block
bgColor#ccccff
public final class ObjectPreserver implements Runnable {
  private static ObjectPreserver lifeLine = new ObjectPreserver();

  private ObjectPreserver() {
    Thread thread = new Thread(this);
    thread.setDaemon(true);
    thread.start(); // Keep this object alive
  }
 
  // Neither this class nor HashMap will be garbage-collected.
  // References from HashMap to other objects will also exhibit this property
  private static final ConcurrentHashMap<Integer,Object> protectedMap 
    = new ConcurrentHashMap<Integer,Object>();
  
  public synchronized void run() {
    try {
      wait();
    } catch (InterruptedException e) { 
      Thread.currentThread().interrupt(); // Reset interrupted status 
    }
  }

  // Objects passed to this method will be preserved until
  // the unpreserveObject method is called
  public static void preserveObject(Object obj) {    
    protectedMap.put(0, obj);  
  }
  
  // Returns the same instance every time
  public static Object getObject() {
    return protectedMap.get(0);	  
  }
  
  // Unprotect the objects so that they can be garbage-collected
  public static void unpreserveObject() {
    protectedMap.remove(0);
  }
}

...