Versions Compared

Key

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

...

In this noncompliant code example, the static initializer started starts a background thread as part of class initialization. The background thread attempted attempts to initialize a database connection but should have waited wait until all members of the ConnectionFactory class, including dbConnection, were are initialized.

Code Block
bgColor#FFcccc
public final class ConnectionFactory {
  private static Connection dbConnection;
  // Other fields ...

  static {
    Thread dbInitializerThread = new Thread(new Runnable() {
        @Override 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>() {
      @Override 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();
  }
}

The static initializer can be used to initialize any other shared class fieldsfield. Alternatively, the fields can be initialized from the initialValue() method.

...

Wiki Markup
<ac:structured-macro ac:name="anchor" ac:schema-version="1" ac:macro-id="35c69f046504ce3d-65fa511f-4c624d1e-a1e5a878-dc15b2c4674e3c7b00eddde6"><ac:parameter ac:name="">CON20-EX1</ac:parameter></ac:structured-macro>
*TSM02-EX0:* Programs are permitted to start a background thread (or threads) during class initialization, provided the thread cannot access any fields. For example, the following {{ObjectPreserver}} class (based on \[[Grand 2002|AA. Bibliography#Grand 02]\]) that follows provides a mechanism for storing object references, which prevents an object from being garbage-collected even when the object is never again dereferenced.

...

Starting and using background threads during class initialization can result in deadlock conditions.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

TSM02-J

low

probable

high

P2

L3

...

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="dfc7c2ea17e1f6e8-9d098a64-40e54fb7-944897d7-1e5f84c8038a20b2028a61b0"><ac:plain-text-body><![CDATA[

[[Bloch 2005b

AA. Bibliography#Bloch 05b]]

8, Lazy Initialization

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="abb447658e3474a6-046f448d-484540d7-bb4482d6-3aeb4db1749b86f6cd1d2298"><ac:plain-text-body><![CDATA[

[[Grand 2002

AA. Bibliography#Grand 02]]

Chapter 5, Creational Patterns, Singleton

]]></ac:plain-text-body></ac:structured-macro>

...