2010-01-22 11 views
97

Sé que usar la palabra clave synchronize antes de que un método proporcione sincronización a ese objeto.
Es decir, 2 hilos que ejecutan la misma instancia del objeto se sincronizarán.
Sin embargo, dado que la sincronización está en el nivel del objeto, 2 hilos que ejecutan instancias diferentes del objeto no se sincronizarán. Entonces, si tenemos una variable estática en una clase java que es llamada por el método, nos gustaría sincronizarla entre las instancias de la clase.
Las dos instancias se ejecutan en 2 subprocesos diferentes.
¿Podemos lograr la sincronización de la siguiente manera?¿Cómo sincronizar una variable estática entre hilos que ejecutan instancias diferentes de una clase en java?

 
public class Test 
{ 
    private static int count = 0; 
    private static final Object lock= new Object();  
    public synchronized void foo() 
    { 
     synchronized(lock) 
    { 
     count++; 
    } 
    } 
} 

¿Es cierto que ya hemos definido 'bloquear' un objeto que es estático y estamos usando la palabra clave sincronizada para que el bloqueo, el recuento varibale estática se ha sincronizado a través de las instancias de la clase de prueba?

+0

¿Puedes formatear tu código poniendo pre alrededor o algo así? –

+0

sí.(Límite de 15 caracteres) – Bozho

+3

¡todas estas respuestas son INÚTILES a menos que el objeto de bloqueo se declare FINAL! –

Respuesta

167

Hay varias maneras de sincronizar el acceso a una variable estática .

  1. Utilice un método estático sincronizado. Esto se sincroniza en el objeto de clase.

    public class Test { 
        private static int count = 0; 
    
        public static synchronized void incrementCount() { 
         count++; 
        } 
    } 
    
  2. sincronizar explícitamente en la clase de objeto.

    public class Test { 
        private static int count = 0; 
    
        public void incrementCount() { 
         synchronized (Test.class) { 
          count++; 
         } 
        } 
    } 
    
  3. Sincronizar en algún otro objeto estático.

    public class Test { 
        private static int count = 0; 
        private static final Object countLock = new Object(); 
    
        public void incrementCount() { 
         synchronized (countLock) { 
          count++; 
         } 
        } 
    } 
    

Método 3 es la mejor en muchos casos debido a que el objeto de bloqueo no está expuesto fuera de su clase.

+1

1. el primero incluso no necesita un objeto de bloqueo, ¿no debería ser el mejor? –

+3

2. declarar recuento como volátil también funcionaría, ya que volátil asegura que la variable esté sincronizada. –

+7

La razón por la que el número 3 es el mejor es que cualquier fragmento de código aleatorio podría sincronizarse en 'Test.class' y potencialmente arruinar tu día. Además, la inicialización de clase se ejecuta con un bloqueo en la clase, por lo que si tienes iniciadores de clase locos, puedes darte dolores de cabeza. 'volátil' no ayuda con' count ++ 'porque es una secuencia de lectura/modificación/escritura. Como se señala en una respuesta diferente, 'java.util.concurrent.atomic.AtomicInteger' es probablemente la elección correcta aquí. – fadden

3

Sí, es cierto.

Si crea dos instancias de la clase

Test t1 = new Test(); 
Test t2 = new Test(); 

Entonces t1.foo y t2.foo tanto en sincronizar en el mismo objeto estático y por lo tanto bloquean entre sí.

+0

uno bloqueará el otro, no el uno al otro a la vez si se tiene cuidado. –

52

Si sólo va a compartir un contador, considerar el uso de un AtomicInteger u otra clase adecuada del paquete java.util.concurrent.atomic:

public class Test { 

    private final static AtomicInteger count = new AtomicInteger(0); 

    public void foo() { 
     count.incrementAndGet(); 
    } 
} 
+0

Esto está disponible solo en java 1.6 –

+1

Está disponible en Java 1.5, no en 1.6. – Pawel

-3

Si se trata sólo de éste número entero, también se puede utilizar

Interlocked.Increment(count)

(espacio de nombres se System.Threading).

+14

El espacio de nombres System.Threading? ¿No es eso C#? –

+0

Me parece C# también. Java tiene java.util.concurrent.atomic.AtomicInteger –

0

Puede sincronizar su código con la clase. Eso sería más simple.

public class Test 
    { 
     private static int count = 0; 
     private static final Object lock= new Object();  
     public synchronized void foo() 
     { 
      synchronized(Test.class) 
     { 
      count++; 
     } 
     } 
    } 

Espero que hagas la respuesta útil.

+1

Esto funcionará, pero como se menciona en @Fadden, tenga en cuenta que cualquier otro hilo también podría sincronizarse en 'Test.class' y afectar el comportamiento. Esta es la razón por la que se prefiere la sincronización en 'lock'. – sbk

+0

Lo que dices es correcto. Es por eso que menciono claramente que lo anterior es el enfoque más simple. –

Cuestiones relacionadas