1

JdbcPersistenceManager には常に jdbcConnection を 1 つだけ持たせ、次の方法でインスタンス化するようにしたいと思います: JdbcConnectionManager.getJdbcConnection()

(2004-11-01 | Head First Design Patterns | O'Reilly Media | 688p | Elisabeth Freeman | ISBN-0596007124) から抜粋した単純なパターンを次に示します。

synchronized() は、「これ」または特定の新しい (静的?) フィールドをロックする必要がありますか? どうすればいいですか?

public class JdbcPersistenceManager implements PersistenceManager {
  private volatile Connection jdbcConnection;
  /* ... */
  private Connection getJdbcConnection() throws JdbcConnectionFailureException {
    if (jdbcConnection == null) {
      synchronized (this) {
        if (jdbcConnection == null) {
          jdbcConnection =
              JdbcConnectionManager.getJdbcConnection(jdbcConnectionParameters);
        }
      }
    }
    // label:here
    return jdbcConnection;
  }
}

jdbcConnection のインスタンス化を想定すると、必要に応じて「label:here」とマークされた時点でも、接続がまだ有効であることを確認し、有効でない場合は再作成する最善の方法は?

ConnectionPooling は、ここでやりたいことではありません。たった1つの接続...「null」または「無効」の場合は再生成/再開します。

編集:

getJdbcConnection にしたいことは次のとおりです。

1) jdbcConnections を配布し、常にそのうちの 1 つだけが存在するようにします (クライアントが 2 つの異なる接続への参照を保持することは許可されません)。

2) なんらかの理由で閉じられた場合、「private volatile Connection jdbcConnection」フィールドを再生成します (つまり、JdbcConnectionManager.getJdbcConnection() を再度呼び出します)。

(たとえば、クライアント 1 が接続を取得しますが、接続を閉じます。クライアント 2 が接続し、接続はnullではありませんが使用できないため、再生成された接続を取得します)。

注:クライアント1が接続を取得するのを止めるものは何もないことを認識していますが、クライアント2は設計上同じ接続を取得し、クライアント1が参照を介して接続を閉じてからわずか1ミリ秒で使用します...それが解決可能かどうかはわかりませんまったく?

4

4 に答える 4

0

シングルトン パターンを実装する場合は、特定のクラスの単一のインスタンスが存在することを確認する必要があります。これが、通常、シングルトン パターンが静的インスタンスを使用して実装される理由です。

同期の問題を回避する最善の方法は、シングルトンをインラインまたは静的初期化子内で初期化することです。これは、クラスが最初にアクセスされたときに初期化が行われ、この初期化が並行性によって損なわれないことが保証されているためです。完全に初期化されるまで使用できます。

public class Singleton {
    private static final Singlenton instance = new Singleton();

    //private constructor here

    public static Singleton getIntance() { return instance; } 
}

ここで、シングルトンを遅延初期化する場合は、複数のスレッドがそのインスタンスを同時に取得しようとする可能性を考慮する必要があります。その場合、クラスへのアクセスを同期します。

public class Singleton {
    private static Singlenton instance;

    //private constructor here

    public static synchronized Singleton getIntance() { 
       if(instance == null) {
            intance = new Singleton();
       }
       return instance; 
    } 
}

同期コードの範囲を縮小することを推奨する人もいます。これにより、特定のスレッドがロックを保持する時間も短縮されます。そのような場合、次のようなことができます。

public class Singleton {
    private static Singlenton instance;

    //private constructor here

    public static Singleton getIntance() { 
       synchronized(Singleton.class) {
          if(instance == null) {
               instance = new Singleton();
          }
       }
       return instance; 
    } 
}

この最後の例では、シングルトン インスタンスが安全に割り当てられると、それを同時に返すことができます。

Singleton を遅延初期化するもう 1 つのパターンは、静的内部クラスを使用することです。

public class Singleton {

  //private constructor

   private static class SingletonHolder { 
       public static final Singleton instance = new Singleton();
  }

   public static Singleton getInstance() {
       return SingletonHolder.instance;
   }
}

これは、内部クラスが最初にアクセスされるまでシングルトンが作成されないことを意味します。これは、getIntance メソッドを呼び出すまで発生しません。繰り返しますが、クラスの初期化はスレッドセーフな方法で行われるため、シングルトンの作成が損なわれないことを確認できます。

于 2012-06-09T20:37:57.773 に答える
0

@edalorzo の包括的なリストに加えて、singletonによって提供されるメカニズムを使用するテクニックがもう 1 つありenumます。ここに良い例があり、このように見えるかもしれません。

public enum SingletonConnection {
  INSTANCE;
  // Not sure if this needs to be volatile.
  private volatile Connection jdbcConnection;

  private SingletonConnection() {
    jdbcConnection = JdbcConnectionManager.getJdbcConnection(jdbcConnectionParameters);
  }

  public Connection getConnection() {
    return jdbcConnection;
  }
}

// use it as ...
SingletonConnection.INSTANCE.getConnection ();

ただし、接続を使用するというアイデアに興味があるかもしれませんThreadLocal

于 2012-06-09T21:46:31.217 に答える
0

はい、synchronized() ロックは単にロックを追跡するためのものであるため、2 つのスレッドがjdbcConnection=NULLを確認したときにjdbcConnectionを次々とインスタンス化することはありません。

その位置での接続の完全性を確認したい場合// label:here。getJdbcConnection() メソッドを再帰的に呼び出すことができます。

return jdbcConnection!=NULL?jdbcConnection:jdbcConnection();
于 2012-06-09T19:34:15.443 に答える
0

二重チェックのロックは、 on ではなくクラスで行う必要がありますthis

if (jdbcConnection == null) {
  synchronized (JdbcPersistenceManager.class) {
    if (jdbcConnection == null) {
      jdbcConnection =
          JdbcConnectionManager.getJdbcConnection(jdbcConnectionParameters);
    }
  }
}

接続チェックに従って、作成後に提案どおりに実行できます。メソッドを再帰的に呼び出すのではなくnullConnectionインスタンスだけを呼び出して、もう一度呼び出しますgetJdbcConnection()

于 2012-06-09T19:57:14.490 に答える