2011-06-16 28 views

Respuesta

63

Intentaré y agregaré un ejemplo para dejarlo más claro.

Como se ha mencionado, sincronizado en Java es una implementación del concepto Monitor. Cuando marca un bloque de código como sincronizado utiliza un objeto como parámetro. Cuando un hilo de ejecución llega a dicho bloque de código, primero debe esperar hasta que no haya otro hilo de ejecución en un bloque sincronizado en ese mismo objeto.

Object a = new Object(); 
Object b = new Object(); 
... 
synchronized(a){ 
    doStuff(); 
} 
... 
synchronized(b){ 
    doSomeStuff(); 
} 
... 
synchronized(a){ 
    doOtherStuff(); 
} 

En el ejemplo anterior, un hilo conductor doOtherStuff() bloquearía otro hilo de entrar en el bloque de código proteger doStuff(). Sin embargo, un hilo podría ingresar al bloque alrededor de doSomeStuff() sin problemas ya que está sincronizado en el Objeto b, no en el Objeto a.

Cuando utiliza el modificador sincronizado en un método de instancia (un método no estático), es muy similar a tener un bloque sincronizado con "this" como argumento. Así, en el siguiente ejemplo, MethodA() y methodB() actuarán de la misma manera:

public synchronized void methodA() { 
    doStuff(); 
} 
... 
public void methodB() { 
    synchronized(this) { 
     doStuff(); 
    } 
} 

Tenga en cuenta que si usted tiene un methodC() de la clase que no está sincronizado y no tiene un bloque sincronizado, nada impedirá que un hilo ingrese a ese método y la programación descuidada podría permitir que ese hilo acceda al código no seguro del objeto.

Si usted tiene un método estático con el modificador sincronizada, es prácticamente el mismo que tiene un bloque sincronizado con ClassName.class como argumento (si tiene un objeto de esa clase, ClassName cn = new ClassName();, puede acceder a ese objeto con Class c = cn.getClass();)

class ClassName { 
    public void static synchronized staticMethodA() { 
    doStaticStuff(); 
    } 
    public static void staticMethodB() { 
    synchronized(ClassName.class) { 
     doStaticStuff(); 
    } 
    } 
    public void nonStaticMethodC() { 
    synchronized(this.getClass()) { 
     doStuff(); 
    } 
    } 
    public static void unSafeStaticMethodD() { 
    doStaticStuff(); 
    } 
} 

Así en el ejemplo anterior, staticMethodA() y staticMethodB() actúan de la misma manera. Un hilo de ejecución también se bloqueará para acceder al bloque de código en nonStaticMethodC() ya que se está sincronizando en el mismo objeto.

Sin embargo, es importante saber que nada impedirá que un subproceso ejecutante acceda a unSafeStaticMethodD(). Incluso si decimos que un método estático "se sincroniza en el objeto Class", no significa que sincroniza todos los accesos a los métodos en esa clase. Simplemente significa que usa el objeto Class para sincronizar. El acceso no seguro todavía es posible.

+0

excelente respuesta y excelente trabajo para explicarlo con ejemplos claros – emilebaizel

15

En resumen, si se sincroniza en un método estático se sincronizará en la clase (objeto) y no en una instancia (objeto). Eso significa que mientras se ejecuta un método estático, toda la clase está bloqueada. Entonces, otros métodos estáticos sincronizados también están bloqueados.

+1

... si también están sincronizados. – Kaj

+0

corregido y editado – PeterMmm

4

La sincronización en Java es básicamente una implementación de monitors. Al sincronizar un método no estático, el monitor pertenece a la instancia. Al sincronizar en un método estático, el monitor pertenece a la clase. La sincronización de un bloque de código es la misma idea, pero el monitor pertenece al objeto especificado. Si puede salirse con la suya, los bloques sincronizados son preferibles porque minimizan el tiempo que cada hilo pasa en el critical section

+2

Simplemente para mejorarlo ligeramente: para los métodos estáticos, el monitor pertenece a la instancia 'Class', no a la '* class *'. Por cierto, esto es muy importante si tienes que usar más cargadores de una clase y más cargadores de una clase cargan la misma clase, entonces tenemos más de una instancia de 'Clase' para la misma clase ... –

+0

@Andreas_D Gracias por la aclaración. No estaba al tanto de ese matiz con los cargadores de múltiples clases. – jpm

3

No hay prácticamente ninguna diferencia entre sincronizar un bloque y sincronizar un método.Básicamente:

void synchronized m() {...} 

es lo mismo que

void m() { synchronized(this) {...} } 

Por comparación, un método sincronizado estático es lo mismo que:

static void m() { synchronized(MyClass.class) {...} } 
0

Amigo, sólo un toque. No se relaciona con su pregunta:

Si Cualquiera métodos * Cosas() no sea

this.a= /*yet another*/ new Object(); 

o

this.b= /*yet another*/ new Object(); 

entonces estás jodido. Porque el bloqueo está dentro del valor, no dentro de la referencia. Ver Java synchronized references

0

Java Thread adquiere un bloqueo a nivel de objeto, cuando entre en un método java ejemplo sincronizado y adquiere un bloqueo nivel clase cuando éste entre en método java síncrona estática. Al usar bloque sincronizado, solo puede bloquear la sección crítica del código y evitar el bloqueo de todo el método, lo que puede degradar el rendimiento.

Cuestiones relacionadas