2012-02-08 9 views
26

, así que estaba probando con la palabra clave synchronized. Aquí hay un ejemplo que he intentado:Aprendizaje de Java, uso de la palabra clave sincronizada

public class MyTest { 
    static int i = 0; 
    public static void main(String[] args) { 
     new Thread(t1).start(); 
     new Thread(t2).start(); 
    } 

    private static void countMe(String name){ 
     i++; 
     System.out.println("Current Counter is: " + i + ", updated by: " + name); 
    } 

    private static Runnable t1 = new Runnable() { 
     public void run() { 
      try{ 
       for(int i=0; i<5; i++){ 
        countMe("t1"); 
       } 
      } catch (Exception e){} 

     } 
    }; 

    private static Runnable t2 = new Runnable() { 
     public void run() { 
      try{ 
       for(int i=0; i<5; i++){ 
        countMe("t2"); 
       } 
      } catch (Exception e){} 
     } 
    }; 
} 

Cuando lo ejecuto, la salida de llamar countMe() método de dos hilos genera esta salida:

Current Counter is: 1 
Current Counter is: 2 
Current Counter is: 4 
Current Counter is: 5 
Current Counter is: 6 
Current Counter is: 7 
Current Counter is: 3 
Current Counter is: 8 
Current Counter is: 9 
Current Counter is: 10 

Y cuando cambio el método countMe() a:

private synchronized static void countMe(){ 
     i++; 
     System.out.println("Current Counter is: " + i); 
} 

puedo obtener este resultado:

Current Counter is: 1 
Current Counter is: 2 
Current Counter is: 3 
Current Counter is: 4 
Current Counter is: 5 
Current Counter is: 6 
Current Counter is: 7 
Current Counter is: 8 
Current Counter is: 9 
Current Counter is: 10 

Aunque esto me permite entender claramente el propósito de synchronized, también quiero saber si hay alguna otra razón por la que podamos usar synchronized. O lo que he hecho aquí, ¿es la única razón por la que necesitamos el uso de esta palabra clave synchronized?

Gracias.

EDIT: Otra cosa que estoy confundido con es que en la primera salida por qué el contador fue a 3 después de 7. Me parece un poco imposible para mí, pero un efecto similar hace suceder cada vez que intento, es esto normal ?

+0

No hay garantía de que los hilos se alternarán. El hilo que contó 3 puede no imprimirse hasta que el otro hilo haya contado hasta 7. –

+0

gracias, pero al igual que después de 7 ¿cómo puede la próxima llamada imprimir 3. Quiero decir que podría imprimir 6 o incluso 5, pero esta parece ser la nueva llamada al método no lo leí después de que fue 3, esto suena muy extraño. ¿Entonces crees que debería ser inteligente usar siempre sincronizados cada vez que tengo que usar el mismo bloque de código de 2 o más hilos? – 911TurboS

+5

Te sugiero que imprimas el nombre de la secuencia y será más obvio dónde está la confusión. La concurrencia es un tema complejo y no hay respuestas simples. Mi preferencia es usar patrones de actor y compartir la menor cantidad de datos posible entre los hilos. idealmente, ninguno. Un hilo que realiza código de manera muy eficiente suele ser más que suficiente. –

Respuesta

24

dos cosas:

primer lugar, no es posible que dos invocaciones de métodos sincronizados en el mismo objeto para intercalar. Cuando un hilo está ejecutando un método sincronizado para un objeto, todos los otros hilos que invocan métodos sincronizados para el mismo bloque de objetos (suspenden la ejecución) hasta que el primer hilo termina con el objeto.

En segundo lugar, cuando sale un método sincronizado, establece automáticamente una relación de pasar antes con cualquier invocación posterior de un método sincronizado para el mismo objeto. Esto garantiza que los cambios en el estado del objeto sean visibles para todos los hilos.

Los métodos sincronizados permiten una estrategia simple para evitar interferencias de hilos y errores de consistencia de memoria: si un objeto es visible para más de un hilo, todas las lecturas o escrituras de las variables de ese objeto se realizan a través de métodos sincronizados. (Una excepción importante: los campos finales, que no pueden modificarse después de que se construye el objeto, se pueden leer de forma segura a través de métodos no sincronizados, una vez que se construye el objeto).

fuente: http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

+0

vulkanino, entonces sería una buena idea usar sincronizados todo el tiempo, si utilizo hilos que acceden al mismo método. – 911TurboS

+0

+1, mejor respuesta que la mía ... – Nim

+0

@ 911TurboS El uso de 'synchronized' en algunos métodos es extremadamente insuficiente para sincronizar correctamente el código multiproceso. Debe tener en cuenta la coherencia de los datos (y probablemente muchas otras cosas). – toto2

11

Vulkanino dio una buena respuesta a su pregunta principal, por lo que sólo referiré a una pregunta sobre la impresión después de 3 7.

El 3 puede imprimir después de la 7 porque no es en realidad mucho más código de bytes en sus declaraciones que el código de Java.

Voy a ampliar eso.

se llama a

System.out.println("Current Counter is: " + i); 

y ocurre en una línea de código Java, pero en realidad lo que sucede es una cadena que se crea y después de que la cadena se pasa a println. El método println en sí tiene que hacer un poco de procesamiento antes de que realmente escriba la línea en la consola.

Conceptualmente, algo como lo siguiente está sucediendo.

String printlnString = "Current Counter is: 3" 
--> maybe the other thread executes here 
System.out.println(printlnString); 
--> or maybe the other thread executes here 
i is now equal to 7 and the console has "Current Counter is: 7" 
println writes "Current Counter is: 3" to console 
+0

En lugar de escribir el contador en la salida, escríbalo en una matriz simple, luego, cuando los hilos terminen, imprima la matriz. – cognacc

Cuestiones relacionadas