¿Cuál es la diferencia entre un método sincronizado y un bloque sincronizado en Java?

¿Cuál es la diferencia entre un método sincronizado y un bloque sincronizado en Java?

He estado buscando la respuesta en la red, la gente parece estar tan insegura sobre esto 🙁

Mi opinión sería que no hay diferencia entre los dos, excepto que el bloque de sincronización podría estar más localizado en el scope y, por lo tanto, el locking será de menor tiempo.

Y en el caso de Lock en un método estático, ¿en qué se toma Lock? ¿Cuál es el significado de un locking en la clase?

Un método sincronizado utiliza el receptor de método como un locking (es decir, this para métodos no estáticos y la clase que lo incluye para métodos estáticos). Synchronized bloques Synchronized usan la expresión como un locking.

Entonces, los siguientes dos métodos son equivalentes desde el locking prospectivo:

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

Para los métodos estáticos, la clase estará bloqueada:

 class MyClass { synchronized static mystatic() { ... } static mystaticeq() { syncrhonized (MyClass.class) { ... } } } 

Para bloques sincronizados, puede usar cualquier objeto no null como un locking:

 synchronized (mymap) { mymap.put(..., ...); } 

Bloquear scope

Para los métodos sincronizados, el locking se mantendrá en todo el scope del método, mientras que en el bloque synchronized , el locking se mantendrá solo durante ese scope del bloque (también conocido como sección crítica). En la práctica, se permite que la JVM optimice eliminando algunas operaciones de la ejecución synchronized bloque si puede demostrar que se puede hacer de manera segura.

Un método sincronizado es la taquigrafía. Esta:

 class Something { public synchronized void doSomething() { ... } public static synchronized void doSomethingStatic() { ... } } 

es, para todos los efectos, equivalente a esto:

 class Something { public void doSomething() { synchronized(this) { ... } } public static void doSomethingStatic() { synchronized(Something.class) { ... } } } 

(Donde Something.class es el objeto de clase para la clase Something ).

De hecho, con un locking sincronizado, puede ser más específico acerca de su locking, y más refinado sobre cuándo quiere usarlo, pero aparte de eso, no hay diferencia.

Sí, esa es una diferencia. La otra es que puedes adquirir un locking en otros objetos además de this .

La diferencia clave es esta: si declara que un método está sincronizado, entonces todo el cuerpo del método se sincroniza; Sin embargo, si usa el bloque sincronizado, puede rodear solo la “sección crítica” del método en el bloque sincronizado, mientras deja el rest del método fuera del bloque.

Si todo el método es parte de la sección crítica, entonces efectivamente no hay diferencia. Si ese no es el caso, entonces debe usar un bloque sincronizado solo alrededor de la sección crítica. Cuantas más afirmaciones tenga en un bloque sincronizado, menos paralelismo general obtendrá, por lo que desea mantenerlas al mínimo.

Un método sincronizado se bloquea en la instancia del objeto en el que está contenido el método.

Donde un bloque sincronizado puede bloquear CUALQUIER objeto, generalmente un objeto mutex definido como una variable de instancia. Esto permite un mayor control sobre qué cerraduras están en funcionamiento.

Mi opinión sería que no hay diferencia entre los dos, excepto que el bloque de sincronización podría estar más localizado en el scope y, por lo tanto, el locking será de menor tiempo.

Sí. Tienes razón. A diferencia de synchronized métodos synchronized , las declaraciones sincronizadas deben especificar el objeto que proporciona el locking intrínseco.

Ejemplo del tutorial de Java:

 public void addName(String name) { synchronized(this) { lastName = name; nameCount++; } nameList.add(name); } 

Las declaraciones sincronizadas también son útiles para mejorar la concurrencia con una sincronización de grano fino. Puede encontrar un buen ejemplo en la misma página de tutorial para el caso de uso a continuación.

Supongamos, por ejemplo, que la clase MsLunch tiene dos campos de instancia, c1 y c2, que nunca se usan juntos. Todas las actualizaciones de estos campos deben estar synchronized , pero no hay ninguna razón para evitar que una actualización de c1 se intercalde con una actualización de c2, y al hacerlo se reduce la concurrencia al crear lockings innecesarios. En lugar de utilizar métodos sincronizados o utilizar el locking asociado a esto, creamos dos objetos únicamente para proporcionar lockings .

Y en el caso de Lock en un método estático, ¿en qué se toma Lock? ¿Cuál es el significado de un locking en la clase?

En este caso, el hilo adquiere el locking intrínseco para el objeto Class asociado a la clase. Por lo tanto, el acceso a los campos estáticos de la clase está controlado por un locking que es distinto del locking para cualquier instancia de la clase.

Cuando crea un método como sincronizado (no static ):

No es posible intercalar dos invocaciones de métodos synchronized en el mismo objeto. 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.

Si haces un método como static synchronized :

No es posible intercalar dos invocaciones de métodos static synchronized en diferentes objetos de la misma clase. Cuando un subproceso ejecuta un método static synchronized para un objeto de Clase A, todos los demás subprocesos que invocan métodos static synchronized en cualquiera de los objetos del bloque Clase A bloquean (suspenden la ejecución) hasta que el primer subproceso finaliza con la ejecución del método.

Encuentra mejores alternativas a la sincronización en esta pregunta SE:

Evitar sincronizado (esto) en Java?