Si un método sincronizado llama a otro método no sincronizado, ¿hay un locking en el método no sincronizado?

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

Si un método sincronizado llama a otro método no sincronizado, ¿hay un locking en el método no sincronizado?

Si y no.

Si está en un método synchronized , las llamadas a otros métodos que también están synchronized por otros hilos están bloqueadas. Sin embargo, las llamadas a métodos no sincronizados por otros hilos no están 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 llama a someSynchronizedMethod() pero sucede que está dentro del método someNonSynchronizedMethod() , aún mantiene el locking. El locking 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 preguntas dos cosas diferentes en tu pregunta:

En Java, si un método sincronizado contiene una llamada a un sistema no sincronizado, ¿puede otro método seguir accediendo al método no sincronizado al mismo tiempo?

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 locking (incluidas las llamadas a otros métodos sincronizados)?

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

Además, recuerde que si el método es static entonces el locking 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 locking está en la instancia de la clase.

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

Hay 2 lockings diferentes en esos 2 casos.

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

Si el hilo A llama al método sincronizado M1 que a su vez llama al método M2 sin sincronizar, el hilo B todavía puede llamar a M2 sin locking.

El método sincronizado adquiere y libera el locking intrínseco en el objeto al que se llama. Es por eso que puede bloquear. El método no sincronizado no intenta adquirir ningún locking (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.

El candado no pertenece al hilo. El locking en realidad pertenece al objeto (o Clase en caso de locking de nivel de clase) y un hilo adquiere un locking en el objeto (o Clase en caso de locking de nivel de clase) dentro de un contexto sincronizado. Ahora, no hay propagación de locking en Java como se discutió anteriormente. Aquí hay 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 Runnable {

 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 dataList = new ArrayList(); 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(); } } 

}

clase pública 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(); }*/ } 

}

Solo he usado el locking Reentrant aquí. Si se ejecuta el código anterior, habrá entrelazado entre el subproceso 1 y el subproceso 3, pero si la parte de locking de la clase Task2 no está comentada, no habrá entrelazado y el subproceso que adquiera el candado primero se completará primero, luego liberará el locking y luego el otro hilo puede continuar.

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

Otro hilo todavía puede invocar el segundo método no sincronizado. Cualquier subproceso puede invocar un método no sincronizado en cualquier momento.