簡體   English   中英

線程安全單例類

[英]Thread Safe singleton class

我寫了一個下面的Singleton類。 我不確定這是否是線程安全的單例類?

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;
    }
}

誰能幫我這個? 對我上面的Singleton課程的任何想法都會有很大的幫助。

更新的代碼: -

我試圖在我的代碼中加入波希米亞建議。 這是更新后的代碼,我得到了 -

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;
    }
}

任何人都可以看看,讓我知道,如果這次我做對了嗎?

謝謝您的幫助。

您正在實現延遲初始化模式 - 首次使用時創建實例。

但是有一個簡單的技巧,可以讓你的代碼並不需要同步的線程執行! 它被稱為按需初始化持有者習語 ,它看起來像這樣:

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的靜態塊被激活時)
  • 類加載器有自己的同步內置,使上述兩點保證是線程安全的

這是我在需要延遲初始化時使用的一個巧妙的小技巧。 您也可以獲得final實例的獎勵,即使它是懶惰創建的。 還要注意代碼的清晰和簡單。

編輯:您應該將所有構造函數設置為私有或受保護。 設置和清空私有構造函數將完成工作

以上所有方法都在急切地初始化對象。 這個怎么樣。 這將幫助您懶惰地初始化您的類。 您可能有重物,並且您不希望在啟動時初始化。

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;

}

} 

不,如果在pulbic方法上返回的值是可更改對象,則它不是線程安全的。

對於這個類是線程安全的一種方法是將其更改為不可變。

為此,您可以像這樣更改此方法:

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 Concurrency in Practice中,您可以看到該不變性的原理。

作為mentiond這篇大文章在這里

這個問題的最佳解決方案是使用靜態字段

public class Singelton {

    private static final Singelton singleObject = new Singelton();

    public Singelton getInstance(){
        return singleObject;
    }
}

不,這並不似乎是線程安全的。 看來你在調用getInstance之后可以訪問可變數據,其中鎖已經被釋放。

在java 1.5版本之后我們可以使用volatile。 如果我們使用volatile java key ward,我們可以創建具有線程安全性的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!");
    }
}

我認為這樣做會做同樣的事情,而不必每次都檢查一下。 static與第一次檢查相同

public class Singl {        
    private static Singl _instance;
    //other vars        
    static{
            //synchronized(Singl.class){//do not need
                    _instance = new Singl();
            //}
    }

     public static Singl getInstance() {
             return _instance;

     }

     private Singl(){
             //initizlize
     }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM