我写了一个下面的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;
}
}
如果这次我做对不对,有人可以看看并告诉我吗?
感谢您的帮助。
答案 0 :(得分:196)
您正在实施lazy initialization模式 - 首次使用时创建实例。
但是有一个简单的技巧可以让你编写不需要同步的线程安全实现!它被称为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
的静态块被激活时)这是我在需要延迟初始化时使用的一个巧妙的小技巧。您还可以获得final
实例的奖励,即使它是懒惰创建的。还要注意代码的清晰和简单。
编辑:您应将所有构造函数设置为private或protected。设置和清空私有构造函数将完成工作
答案 1 :(得分:15)
以上所有方法都在急切地初始化对象。这个怎么样。这将帮助您懒惰地初始化您的类。你可能有重物,你不想在启动时初始化。
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;
}
}
答案 2 :(得分:2)
不,如果在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中,您可以看到不可变性的原理。
答案 3 :(得分:1)
正如这篇伟大的文章here中提到的那样:
此问题的最佳解决方案是使用静态字段
public class Singelton {
private static final Singelton singleObject = new Singelton();
public Singelton getInstance(){
return singleObject;
}
}
答案 4 :(得分:0)
不,这不是出现是线程安全的。您可以在调用getInstance
之后访问可变数据,其中锁定已被释放。
答案 5 :(得分:0)
在Java 1.5版本之后,我们可以使用volatile。如果我们使用易失性Java密钥区,则可以创建线程安全的singlton类,因为实例变量也与Other线程共享。
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!");
}
}
答案 6 :(得分:0)
这应该是使用双重检查锁定原则实现单例模式的正确方法:
values.xml
答案 7 :(得分:-1)
我认为这样做会做同样的事情,而不必每次都检查一下。 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
}
}