web-dev-qa-db-ja.com

スレッドセーフシングルトンクラス

以下のシングルトンクラスを書きました。これがスレッドセーフなシングルトンクラスであるかどうかわかりませんか?

public class CassandraAstyanaxConnection {

    private static CassandraAstyanaxConnection _instance;
    private AstyanaxContext<Keyspace> context;
    private Keyspace keyspace;
    private ColumnFamily<String, String> emp_cf;



    public static synchronized CassandraAstyanaxConnection getInstance() {
        if (_instance == null) {
            _instance = new CassandraAstyanaxConnection();
        }
        return _instance;
    }

    /**
     * Creating Cassandra connection using Astyanax client
     *
     */
    private CassandraAstyanaxConnection() {

        context = new AstyanaxContext.Builder()
        .forCluster(ModelConstants.CLUSTER)
        .forKeyspace(ModelConstants.KEYSPACE)
        .withAstyanaxConfiguration(new AstyanaxConfigurationImpl()      
            .setDiscoveryType(NodeDiscoveryType.RING_DESCRIBE)
        )
        .withConnectionPoolConfiguration(new ConnectionPoolConfigurationImpl("MyConnectionPool")
            .setPort(9160)
            .setMaxConnsPerHost(1)
            .setSeeds("127.0.0.1:9160")
        )
        .withAstyanaxConfiguration(new AstyanaxConfigurationImpl()      
            .setCqlVersion("3.0.0")
            .setTargetCassandraVersion("1.2"))
        .withConnectionPoolMonitor(new CountingConnectionPoolMonitor())
        .buildKeyspace(ThriftFamilyFactory.getInstance());

        context.start();
        keyspace = context.getEntity();

        emp_cf = ColumnFamily.newColumnFamily(
            ModelConstants.COLUMN_FAMILY, 
            StringSerializer.get(), 
            StringSerializer.get());
    }

    /**
     * returns the keyspace
     * 
     * @return
     */
    public Keyspace getKeyspace() {
        return keyspace;
    }

    public ColumnFamily<String, String> getEmp_cf() {
        return emp_cf;
    }
}

誰でもこれで私を助けることができますか?上記のシングルトンクラスに関するご意見は、大変参考になります。

更新コード:-

私は自分のコードにボヘミアンの提案を取り入れようとしています。これが更新されたコードです。

public class CassandraAstyanaxConnection {
    private static class ConnectionHolder {
        static final CassandraAstyanaxConnection connection = new CassandraAstyanaxConnection();
    }
    public static CassandraAstyanaxConnection getInstance() {
        return ConnectionHolder.connection;
    }
    /**
     * Creating Cassandra connection using Astyanax client
     *
     */
    private CassandraAstyanaxConnection() {
        context = new AstyanaxContext.Builder()
        .forCluster(ModelConstants.CLUSTER)
        .forKeyspace(ModelConstants.KEYSPACE)
        .withAstyanaxConfiguration(new AstyanaxConfigurationImpl()      
        .setDiscoveryType(NodeDiscoveryType.RING_DESCRIBE)
                )
                .withConnectionPoolConfiguration(new ConnectionPoolConfigurationImpl("MyConnectionPool")
                .setPort(9160)
                .setMaxConnsPerHost(1)
                .setSeeds("127.0.0.1:9160")
                        )
                        .withAstyanaxConfiguration(new AstyanaxConfigurationImpl()      
                        .setCqlVersion("3.0.0")
                        .setTargetCassandraVersion("1.2"))
                        .withConnectionPoolMonitor(new CountingConnectionPoolMonitor())
                        .buildKeyspace(ThriftFamilyFactory.getInstance());
        context.start();
        keyspace = context.getEntity();
        emp_cf = ColumnFamily.newColumnFamily(
                ModelConstants.COLUMN_FAMILY, 
                StringSerializer.get(), 
                StringSerializer.get());
    }
    /**
     * returns the keyspace
     * 
     * @return
     */
    public Keyspace getKeyspace() {
        return keyspace;
    }
    public ColumnFamily<String, String> getEmp_cf() {
        return emp_cf;
    }
}

誰もが見て、今回はそれが正しかったかどうかを教えてもらえますか?

助けてくれてありがとう。

58
arsenal

lazy初期化 パターン-インスタンスが最初に使用されるときに作成される場所を実装しています。

しかし、同期を必要としないスレッドセーフ実装をコーディングできる簡単なトリックがあります! Initialization-on-demand holder idiom と呼ばれ、次のようになります。

_public class CassandraAstyanaxConnection {

    private CassandraAstyanaxConnection(){ }        

    private static class Holder {
       private static final CassandraAstyanaxConnection INSTANCE = new CassandraAstyanaxConnection();
    }

    public static CassandraAstyanaxConnection getInstance() {
        return Holder.INSTANCE;
    }
    // rest of class omitted
}
_

このコードは、getInstance()の最初の呼び出しでインスタンスを初期化し、クラスローダーのコントラクトのために同期を必要としないことが重要です。

  • クラスローダーは、最初にアクセスされたときにクラスをロードします(この場合、HolderのアクセスはgetInstance()メソッド内のみです)
  • クラスがロードされ、誰でも使用できるようになる前に、すべての静的初期化子が実行されることが保証されます(Holderの静的ブロックが起動するとき)
  • クラスローダーには、上記の2つのポイントがスレッドセーフであることを保証する独自の同期が組み込まれています。

怠laな初期化が必要なときはいつでも使用する、ちょっとした小技です。また、finalインスタンスのボーナスも取得されますが、それは遅延して作成されます。また、コードがどれほどクリーンでシンプルであるかに注意してください。

Edit:すべてのコンストラクターをprivateまたはprotectedとして設定する必要があります。設定して空のプライベートコンストラクターが作業を行います

203
Bohemian

上記のすべてのメソッドは、オブジェクトを積極的に初期化しています。これはどう。これは、urクラスを遅延的に初期化するのに役立ちます。重いオブジェクトがあり、起動時に初期化したくない場合があります。

public class MySinglton { 

  private MySinglton (){}

  private static volatile MySinglton s;

  public static MySinglton getInstance(){

   if (s != null ) return s;

    synchronized(MySinglton.class){

     if (s == null ) {

      s = new MySinglton();
     }
  }

  return s;

}

} 
16
Mohammad Adnan

いいえ、pulbicメソッドで返される値が変更可能なオブジェクトである場合、スレッドセーフではありません。

このクラスに対してスレッドセーフにする方法の1つは、不変に変更することです。

これを行うには、次のようにこのメソッドを変更できます。

public Keyspace getKeyspace() {
    // make a copy to prevent external user to modified or ensure that Keyspace is immutable, in that case, you don't have to make a copy
    return new Keyspace( keyspace );
}

public ColumnFamily<String, String> getEmp_cf() {
    // Same principle here. If ColumnFamily is immutable, you don't have to make a copy. If its not, then make a copy
    return new ColumnFamily( emp_cf );
}

この本では、 Javaの同時実行性 その不変性の原理を見ることができます。

2
Jose Renato

このすばらしい記事で言及されているように here

public class Singelton { private static final Singelton singleObject = new Singelton(); public Singelton getInstance(){ return singleObject; } }

2
Andro Secy

Java 1.5バージョンではvolatileを使用できます。volatileJava key wardを使用した場合、インスタンス変数はOtherと共有するため、スレッドセーフでsingltonクラスを作成できますスレッドも。

public class SingleWithThreadSafe {

    // create an object static referance of SingleWithThreadSafe with volatile
    private static volatile SingleWithThreadSafe instance = null;

    // if we make the constructor private so that this class cannot be
    // instantiated from out side of class
    private SingleWithThreadSafe() {
    }

    // Get only object available
    public static SingleWithThreadSafe getInstance() {
        if (instance == null) {
            instance = new SingleWithThreadSafe();
        }
        return instance;
    }

    public void showMessage() {
        System.out.println("Hello World!");
    }
}
0

いいえ、これはappearではなく、スレッドセーフです。ロックが解除されたgetInstanceの呼び出し後にアクセス可能な可変データがあるようです。