3

我相信我写的下面的 Singleton 类是Thread Safe.

在某些情况下,双重检查锁定模式显然可能会遇到问题(我已经看到人们警告过它,尽管这是不久前的事情,所以我现在只是在谷歌上搜索答案)

我现在不确定,我下面的 Singleton 类中的 Double Checked 锁定模式是否会有任何问题。我添加了双重检查锁定模式,以使程序运行得稍微快一些。

    public class CassandraAstyanaxConnection {

        private static CassandraAstyanaxConnection _instance;
        private static final Object syncObject = new Object();
        private AstyanaxContext<Keyspace> context;
        private Keyspace keyspace;
        private ColumnFamily<String, String> emp_cf;


       public static CassandraAstyanaxConnection getInstance() {
            if (_instance == null) {
                     synchronized(syncObject) {
                        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 {
       public static 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;
        }
}

让我知道这是否正确。

4

5 回答 5

2

我非常喜欢以下惰性初始化单例模式:

public final class CassandraAstyanaxConnection {

   ...

   private static class ConnectionHolder {
       public static CassandraAstyanaxConnection connection = new CassandraAstyanaxConnection()
   }

   public static CassandraAstyanaxConnection getInstance() {
        return ConnectionHolder.connection;
   }

   ...
}
于 2013-04-19T07:28:02.243 回答
1

创建线程安全的单例类的最好方法是使用枚举

public enum CassandraAstyanaxConnection {

       INSTANCE;
       //fields

        public void initializeConnection() {
            //Move work from private constructor here.
        }


}

我想这样的事情应该可以工作。

于 2013-04-19T07:19:32.167 回答
1

您的 DCL 已损坏,_instance 必须是 volatile 才能正常工作

private static volatile CassandraAstyanaxConnection _instance;

在您的情况下,最好的解决方案是

private static CassandraAstyanaxConnection _instance = new CassandraAstyanaxConnection();
...
public static CassandraAstyanaxConnection getInstance() {
    return _instance;
}

因为 getInstance() 是唯一的公共方法,所以它是惰性的。只有当您调用 getInstance() 类时才会加载并创建实例。这就是 Holder 成语的含义。在您的情况下,您不需要它。整个班级都像那个成语一样工作

于 2013-04-19T07:30:03.237 回答
0

一个好的单身人士:

1- 上课final

2-制作static实例final

3-覆盖readResolve()以返回实例。

4-为了完美,从clone().

5-同步getInstance()

6-制作默认构造函数private

按照这个来看看双重检查锁定习语是否真的有效。

最好的方法是使用enum. 这种东西:

public enum DBConn{
 CON_INSTANCE;
 private CassandraAstyanaxConnection connection;
 public synchronized CassandraAstyanaxConnection getConnection(){
   if(connection == null){
      // instantiate a connection
   }
   return connection;
 }
}

通过访问它DBConn.CON_INSTANCE.getConnection();

于 2013-04-19T07:28:36.487 回答
0

如果要对静态字段进行延迟初始化,最好的模式是“使用持有者类进行延迟初始化”:

public class CassandraAstyanaxConnection {
    private static class ConnectionHolder {
       static final CassandraAstyanaxConnection field = 
              new CassandraAstyanaxConnection();
    }

    public static CassandraAstyanaxConnection getInstance() { 
         return ConnectionHolder.field; 
    }
...
}

在这种情况下,延迟初始化由 JVM 保证,在ConnectionHolder类加载之前不会初始化该字段。

于 2013-04-19T07:29:26.200 回答