简体   繁体   English

线程安全单例类

[英]Thread Safe singleton class

I wrote a below Singleton class. 我写了一个下面的Singleton类。 I am not sure whether this is thread safe singleton class or not? 我不确定这是否是线程安全的单例类?

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

Can anyone help me with this? 谁能帮我这个? Any thoughts on my above Singleton class will be of great help. 对我上面的Singleton课程的任何想法都会有很大的帮助。

Updated Code:- 更新的代码: -

I am trying to incorporate Bohemian suggestion in my code. 我试图在我的代码中加入波希米亚建议。 Here is the updated code, I got- 这是更新后的代码,我得到了 -

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

Can anyone take a look and let me know if this time I got it right or not? 任何人都可以看看,让我知道,如果这次我做对了吗?

Thanks for the help. 谢谢您的帮助。

You are implementing the lazy initialization pattern - where the instance is created when first used. 您正在实现延迟初始化模式 - 首次使用时创建实例。

But there is a simple trick that allows you to code a threadsafe implementation that doesn't require synchronization! 但是有一个简单的技巧,可以让你的代码并不需要同步的线程执行! It is known as the Initialization-on-demand holder idiom , and it looks like this: 它被称为按需初始化持有者习语 ,它看起来像这样:

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
}

This code initializes the instance on the first calling of getInstance() , and importantly doesn't need synchronization because of the contract of the class loader: 这段代码在第一次调用getInstance()初始化实例,并且由于类加载器的契约,重要的是不需要同步:

  • the class loader loads classes when they are first accessed (in this case Holder 's only access is within the getInstance() method) 类加载器在首次访问时加载类(在这种情况下, Holder的唯一访问是在getInstance()方法中)
  • when a class is loaded, and before anyone can use it, all static initializers are guaranteed to be executed (that's when Holder 's static block fires) 当一个类被加载,并且在任何人都可以使用它之前,所有的静态初始化器都保证被执行(那就是当Holder的静态块被激活时)
  • the class loader has its own synchronization built right in that make the above two points guaranteed to be threadsafe 类加载器有自己的同步内置,使上述两点保证是线程安全的

It's a neat little trick that I use whenever I need lazy initialization. 这是我在需要延迟初始化时使用的一个巧妙的小技巧。 You also get the bonus of a final instance, even though it's created lazily. 您也可以获得final实例的奖励,即使它是懒惰创建的。 Also note how clean and simple the code is. 还要注意代码的清晰和简单。

Edit: You should set all constructors as private or protected. 编辑:您应该将所有构造函数设置为私有或受保护。 Setting and empty private constructor will do the work 设置和清空私有构造函数将完成工作

all above methods are eagerly initializing object. 以上所有方法都在急切地初始化对象。 how about this. 这个怎么样。 This will help you to initialize ur class lazily. 这将帮助您懒惰地初始化您的类。 You may have heavy object and you don't want to initialize on startup. 您可能有重物,并且您不希望在启动时初始化。

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;

}

} 

No, its not thread-safe if the values returned on the pulbic methods are changeble objects. 不,如果在pulbic方法上返回的值是可更改对象,则它不是线程安全的。

To this class be Thread-safe one way is to change it to be immutable. 对于这个类是线程安全的一种方法是将其更改为不可变。

To do that, you could change this methods like this: 为此,您可以像这样更改此方法:

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

In this book Java Concurrency in Practice you can see the principle of that immutability. 在本书Java Concurrency in Practice中,您可以看到该不变性的原理。

As mentiond in this great article here : 作为mentiond这篇大文章在这里

The best solution to this problem is [...] to use a static field 这个问题的最佳解决方案是使用静态字段

public class Singelton {

    private static final Singelton singleObject = new Singelton();

    public Singelton getInstance(){
        return singleObject;
    }
}

No, this does not appear to be thread-safe. 不,这并不似乎是线程安全的。 It appears that you there is mutable data accessible after the call to getInstance , where the lock would have been released. 看来你在调用getInstance之后可以访问可变数据,其中锁已经被释放。

After java 1.5 version we can use volatile. 在java 1.5版本之后我们可以使用volatile。 If we used volatile java key ward, we can create singlton class with thread safe, Because instance variable share with Other thread as well. 如果我们使用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!");
    }
}

I think this will do the same thing without having to check for instance every time. 我认为这样做会做同样的事情,而不必每次都检查一下。 static is the same as check first time 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