Subproceso Safe singleton class

Escribí una clase de Singleton debajo. No estoy seguro de si esta es la clase singleton segura o no?

public class CassandraAstyanaxConnection { private static CassandraAstyanaxConnection _instance; private AstyanaxContext context; private Keyspace keyspace; private ColumnFamily 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 getEmp_cf() { return emp_cf; } } 

Puede alguien ayudarme con esto? Cualquier idea sobre mi clase Singleton anterior será de gran ayuda.

Código actualizado: –

Estoy tratando de incorporar la sugerencia de Bohemia en mi código. Aquí está el código actualizado, tengo-

 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 getEmp_cf() { return emp_cf; } } 

¿Puede alguien echar un vistazo y decirme si esta vez lo hice bien o no?

Gracias por la ayuda.

Está implementando el patrón de inicialización diferido, donde se crea la instancia cuando se usa por primera vez.

¡Pero hay un truco simple que le permite codificar una implementación de ejecución de hilos que no requiere sincronización! Se lo conoce como el idioma del titular de inicialización según demanda , y se ve así:

 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 } 

Este código inicializa la instancia en la primera llamada de getInstance() y, lo que es más importante, no necesita sincronización debido al contrato del cargador de clases:

  • el cargador de clases carga clases cuando se accede por primera vez (en este caso, el único acceso del Holder encuentra dentro del método getInstance() )
  • cuando se carga una clase, y antes de que alguien pueda usarla, se garantiza que se ejecutarán todos los inicializadores estáticos (eso es cuando el bloque estático de Holder dispara)
  • el cargador de clases tiene su propia sincronización integrada que hace que los dos puntos anteriores garanticen su enhebrado

Es un pequeño truco que uso cada vez que necesito una inicialización lenta. También obtienes la bonificación de una instancia final , aunque se haya creado de forma perezosa. También tenga en cuenta lo limpio y simple que es el código.

Editar: debe configurar todos los constructores como privados o protegidos. Configuración y el constructor privado vacío harán el trabajo

todos los métodos anteriores están ansiosamente inicializando el objeto. Qué tal esto. Esto te ayudará a inicializar tu clase perezosamente. Puede tener un objeto pesado y no desea inicializar al inicio.

 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, no es seguro para subprocesos si los valores devueltos en los métodos pulbicos son objetos modificables.

Para esta clase, es seguro para el hilo de una manera es cambiarlo para que sea inmutable.

Para hacer eso, puedes cambiar este método así:

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

En este libro Java Concurrency in Practice se puede ver el principio de esa inmutabilidad.

Como se menciona en este gran artículo aquí :

La mejor solución para este problema es […] usar un campo estático

 public class Singelton { private static final Singelton singleObject = new Singelton(); public Singelton getInstance(){ return singleObject; } } 

No, esto no parece ser seguro para subprocesos. Parece que hay datos mutables accesibles después de la llamada a getInstance , donde se habría liberado el locking.

Creo que esto hará lo mismo sin tener que verificar, por ejemplo, todo el tiempo. estática es lo mismo que verificar la primera vez

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