Program Tip

스레드 세이프 싱글 톤 클래스

programtip 2020. 12. 9. 21:40
반응형

스레드 세이프 싱글 톤 클래스


아래 싱글 톤 클래스를 작성했습니다. 이것이 스레드로부터 안전한 싱글 톤 클래스인지 확실하지 않습니까?

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

누구든지 이번에 내가 옳았는지 아닌지 살펴보고 알려줄 수 있습니까?

도와 주셔서 감사합니다.


처음 사용할 때 인스턴스가 생성되는 지연 초기화 패턴을 구현하고 있습니다.

그러나 동기화 필요 없는 스레드 세이프 구현을 코딩 할 수있는 간단한 트릭이 있습니다 ! 이것은 Initialization-on-demand 홀더 관용구 로 알려져 있으며 다음과 같습니다.

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느리게 생성 되더라도 인스턴스 의 보너스도받습니다 . 또한 코드가 얼마나 깔끔하고 단순한 지 주목하십시오.

편집 : 모든 생성자를 개인 또는 보호로 설정해야합니다. 개인 생성자를 설정하고 비어 있으면 작업이 수행됩니다.


위의 모든 방법은 열심히 개체를 초기화합니다. 이건 어때. 이것은 당신이 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;

}

} 

아니요, 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;
    }
}

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.


After java 1.5 version we can use 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.

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

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
     }

}

참고URL : https://stackoverflow.com/questions/16106260/thread-safe-singleton-class

반응형