2012-03-01 13 views
25

En Java, si un método sincronizado contiene una llamada a un sistema no sincronizado, puede otro método acceder al método no sincronizado ¿al mismo tiempo? Básicamente, lo que estoy preguntando es que todo en el método sincronizado tiene un bloqueo (incluidas las llamadas a otros métodos sincronizados)? Muchas graciasSi un método sincronizado llama a otro método no sincronizado, ¿hay un bloqueo en el método no sincronizado

+2

¿Algún comentario sobre mi respuesta? Por favor, acéptalo si te ayudó. – Gray

+0

Creo que se debe aceptar la respuesta de Gray ya que responde exactamente lo que se le pide. – Sankalp

Respuesta

45

Si está en un método synchronized, las llamadas a otros métodos que también son synchronized por otros hilos están bloqueadas. Sin embargo, las llamadas a métodos no sincronizados por otros hilos son no bloqueadas; cualquiera puede llamarlas al mismo tiempo.

public synchronized void someSynchronizedMethod() { 
    ... 
    someNonSynchronizedMethod(); 
    ... 
} 

// anyone can call this method even if the someSynchronizedMethod() method has 
// been called and the lock has been locked 
public void someNonSynchronizedMethod() { 
    ... 
} 

Además, si se llama a someSynchronizedMethod() pero sucede estar dentro del método someNonSynchronizedMethod(), todavía se mantiene el bloqueo. El bloqueo se habilita cuando ingresa un bloque sincronizado y se desactiva cuando sale de ese método. Puede llamar a todo tipo de otros métodos no sincronizados y aún estarán bloqueados.

Pero usted está pidiendo dos cosas diferentes en su pregunta:

En Java, si un método sincronizado contiene una llamada a una, puede otro método todavía acceso al método no sincronizada no sincronizada al mismo ¿hora?

Sí. Otros métodos pueden acceder a métodos no sincronizados.

Básicamente lo que estoy preguntando es que todo en el método sincronizado tiene un bloqueo (incluidas las llamadas a otros métodos sincronizados)?

Uh, sí. Otras llamadas a sincronizados los métodos están bloqueados. Pero los métodos no sincronizados no están bloqueados.

Además, recuerde que si el método es static, entonces el bloqueo está en el objeto Class en el ClassLoader.

// this locks on the Class object in the ClassLoader 
public static synchronized void someStaticMethod() { 

Si el método es un método de instancia, entonces el bloqueo está en la instancia de la clase.

// this locks on the instance object that contains the method 
public synchronized void someInstanceMethod() { 

Hay 2 cerraduras diferentes en esos 2 casos.

Por último, cuando se trata de synchronized métodos de instancia, cada instancia de la clase es lo que está bloqueado. Esto significa que dos subprocesos podrían estar en el mismo método synchronized al mismo tiempo con diferentes instancias . Pero si 2 hilos intentan operar en los métodos synchronized en la misma instancia, uno bloqueará hasta que el otro salga del método.

+0

Así que supongo que no sería una buena idea llamar a métodos no sincronizados dentro de sincronizados ... porque pueden ser llamados al mismo tiempo por algún otro método. – dido

+3

Si esto provoca que 2 hilos accedan a los datos que deben sincronizarse, entonces sí, no es una buena idea. Sin embargo, esto sucede todo el tiempo con 'toString()' y otros métodos. Simplemente depende de su objeto y el caso de uso. – Gray

+1

Me gustaría agregar aquí, también, que un método sincronizado se puede llamar simultáneamente varias veces, siempre que se llame a diferentes objetos. El bloqueo se aplica al objeto específico, la instancia de la clase, a menos que el método sea estático. Creo que es fácil olvidar esto, ya que muchas personas (incluidos todos los carteles actuales) hablan de un bloqueo del método como si se aplicara independientemente de la instancia del objeto. – arcy

2

Si el hilo A llama al método sincronizado M1 que a su vez llama al método M2 no sincronizado, el hilo B aún puede llamar a M2 sin bloqueo.

El método sincronizado adquiere y libera el bloqueo intrínseco del objeto al que se llama. Es por eso que puede bloquear. El método no sincronizado no intenta adquirir ningún bloqueo (a menos que se haga explícitamente en el código).

Por lo tanto, si necesita garantizar la exclusión mutua para M2 también, debe sincronizar independientemente de si sus llamadores (como M1) están sincronizados o no.

0

La cerradura pertenece al hilo , no al método (o más precisamente, su marco de pila). Da la casualidad de que si tienes un método sincronizado, tienes la garantía de que el hilo poseerá el bloqueo antes de que comience el cuerpo del método, y lo lanzará después.

Otro subproceso aún puede invocar el segundo método no sincronizado. Cualquier subproceso puede invocar un método no sincronizado en cualquier momento.

2

El candado no pertenece al hilo. El bloqueo en realidad pertenece al objeto (o Clase en caso de bloqueo de nivel de clase) y un hilo adquiere un bloqueo en el objeto (o Clase en caso de bloqueo de nivel de clase) dentro de un contexto sincronizado. Ahora, no hay propagación de bloqueo en java como se discutió anteriormente. He aquí una pequeña demostración:

clase pública TestThread {

/** 
* @param args 
* @throws InterruptedException 
*/ 
public static void main(String[] args) throws InterruptedException { 
    // TODO Auto-generated method stub 
    ThreadCreator1 threadCreator1 = new ThreadCreator1(); 
    ThreadCreator2 threadCreator2 = new ThreadCreator2(); 

    Thread t1 = new Thread(threadCreator1,"Thread 1"); 
    Thread t3 = new Thread(threadCreator1,"Thread 3"); 
    Thread t2 = new Thread(threadCreator2,"Thread 2"); 

    t1.start(); 
    Thread.sleep(2000); 
    t3.start(); 

} 

}

clase pública ThreadCreator1 implementa Ejecutable {

private static final Task task= new Task(); 
private static final Task2 task2= new Task2(); 

@Override 

public void run() { 

    try { 

     if(Thread.currentThread().getName().equals("Thread 1")) 
      task.startTask2(task2); 
     if(Thread.currentThread().getName().equals("Thread 3")) 
      task2.startTask(); 

    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    // TODO Auto-generated method stub 

    /**/ 

    } 
} 

clase pública tarea {

public static final Task task = new Task(); 
public static List<String> dataList = new ArrayList<String>(); 
ReentrantLock lock = new ReentrantLock(); 



public void startTask2(Task2 task2) throws InterruptedException 
{ 

    try{ 

     lock.lock(); 
     //new Task2().startTask(); 
     task2.startTask(); 
    } 
    catch(Exception e) 
    { 

    } 
    finally{ 
     lock.unlock(); 
    } 
} 

}

public class {Task2

ReentrantLock lock = new ReentrantLock(); 
public void startTask() throws InterruptedException 
{ 

    try{ 
     //lock.lock(); 
     for(int i =0 ;i< 10;i++) 
    { 
     System.out.println(" *** Printing i:"+i+" for:"+Thread.currentThread().getName()); 
     Thread.sleep(1000); 
    } 
    } 
    catch(Exception e) 
    { 

    } 
    /*finally 
    { 
     lock.unlock(); 
    }*/ 
} 

}

Sólo he utilizado Reentrante bloquear aquí. Si se ejecuta el código anterior, habrá entrelazado entre el subproceso 1 y el subproceso 3, pero si la parte de bloqueo de la clase Task2 no está comentada, no habrá entrelazado y el subproceso que adquiera primero el bloqueo se completará por completo, luego liberará el bloqueo y luego el otro hilo puede continuar.

Cuestiones relacionadas