¿Alguien puede decirme la ventaja del método sincronizado sobre el bloque sincronizado con un ejemplo?
java
multithreading
concurrency
locking
synchronized
Guerrero
fuente
fuente
Respuestas:
No existe una clara ventaja de utilizar el método sincronizado sobre el bloque.
Quizás el único (pero no lo llamaría una ventaja) es que no necesita incluir la referencia del objeto
this
.Método:
Bloquear:
¿Ver? Ninguna ventaja en absoluto.
Los bloques no tienen ventajas sobre los métodos, sin embargo, sobre todo en la flexibilidad porque se puede utilizar como otro objeto de bloqueo, mientras que la sincronización del método encerraría todo el objeto.
Comparar:
vs.
Además, si el método crece, aún puede mantener la sección sincronizada separada:
fuente
synchronized
bloque se implementa utilizando dos instruccionesmonitorenter
ymonitorexit
, además , un controlador de excepciones que garantiza quemonitorexit
se llame incluso en el caso excepcional. Todo eso se guarda al usar unsynchronized
método.La única diferencia real es que un bloque sincronizado puede elegir en qué objeto se sincroniza. Un método sincronizado solo puede usar
'this'
(o la instancia de clase correspondiente para un método de clase sincronizado). Por ejemplo, estos son semánticamente equivalentes:Este último es más flexible ya que puede competir por el bloqueo asociado de cualquier objeto, a menudo una variable miembro. También es más granular porque podría tener código concurrente ejecutándose antes y después del bloque pero aún dentro del método. Por supuesto, podría usar un método sincronizado fácilmente refactorizando el código concurrente en métodos separados no sincronizados. Use lo que haga que el código sea más comprensible.
fuente
Método sincronizado
Pros:
Contras:
Bloque sincronizado
Pros:
Contras:
Personalmente, prefiero usar métodos sincronizados con clases enfocadas solo a lo que necesita sincronización. Dicha clase debería ser lo más pequeña posible y, por lo tanto, debería ser fácil revisar la sincronización. Otros no deberían tener que preocuparse por la sincronización.
fuente
La principal diferencia es que si usa un bloque sincronizado puede bloquear un objeto que no sea este, lo que le permite ser mucho más flexible.
Suponga que tiene una cola de mensajes y múltiples productores y consumidores de mensajes. No queremos que los productores interfieran entre sí, pero los consumidores deberían poder recuperar los mensajes sin tener que esperar a los productores. Entonces solo creamos un objeto
Y a partir de ahora, cada vez que un productor quiera agregar un nuevo mensaje, simplemente nos quedaremos con eso:
Por lo tanto, los consumidores aún pueden leer y los productores estarán bloqueados.
fuente
Método sincronizado
Los métodos sincronizados tienen dos efectos.
Primero, 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 objeto (suspender la ejecución) hasta que el primer hilo se hace con el objeto.
En segundo lugar, cuando sale un método sincronizado, establece automáticamente una relación de suceso anterior 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.
Tenga en cuenta que los constructores no se pueden sincronizar: el uso de la palabra clave sincronizada con un constructor es un error de sintaxis. Sincronizar constructores no tiene sentido, porque solo el hilo que crea un objeto debe tener acceso a él mientras se está construyendo.
Declaración sincronizada
A diferencia de los métodos sincronizados, las declaraciones sincronizadas deben especificar el objeto que proporciona el bloqueo intrínseco: a menudo lo uso para sincronizar el acceso a una lista o mapa, pero no quiero bloquear el acceso a todos los métodos del objeto.
P: Bloqueos intrínsecos y sincronización La sincronización se basa en una entidad interna conocida como bloqueo intrínseco o bloqueo de monitor. (La especificación API a menudo se refiere a esta entidad simplemente como un "monitor".) Los bloqueos intrínsecos desempeñan un papel en ambos aspectos de la sincronización: imponen el acceso exclusivo al estado de un objeto y establecen relaciones previas que son esenciales para la visibilidad.
Cada objeto tiene un bloqueo intrínseco asociado. Por convención, un hilo que necesita acceso exclusivo y consistente a los campos de un objeto tiene que adquirir el bloqueo intrínseco del objeto antes de acceder a ellos, y luego liberar el bloqueo intrínseco cuando se hace con ellos. Se dice que un subproceso posee el bloqueo intrínseco entre el momento en que adquirió el bloqueo y lo liberó. Mientras un hilo posea un bloqueo intrínseco, ningún otro hilo puede adquirir el mismo bloqueo. El otro hilo se bloqueará cuando intente adquirir el bloqueo.
Verificación cruzada de diferentes salidas con método sincronizado, bloque y sin sincronización.
fuente
Nota: los métodos y bloques estáticos sincronizados funcionan en el objeto Class.
fuente
Cuando el compilador de Java convierte su código fuente en código de bytes, maneja métodos sincronizados y bloques sincronizados de manera muy diferente.
Cuando la JVM ejecuta un método sincronizado, el hilo de ejecución identifica que la estructura method_info del método tiene establecido el indicador ACC_SYNCHRONIZED, luego adquiere automáticamente el bloqueo del objeto, llama al método y libera el bloqueo. Si se produce una excepción, el subproceso libera automáticamente el bloqueo.
Sin embargo, la sincronización de un bloque de método omite el soporte incorporado de la JVM para adquirir el bloqueo de un objeto y el manejo de excepciones y requiere que la funcionalidad se escriba explícitamente en código de byte. Si lee el código de bytes de un método con un bloque sincronizado, verá más de una docena de operaciones adicionales para administrar esta funcionalidad.
Esto muestra llamadas para generar un método sincronizado y un bloque sincronizado:
El
synchronizedMethodGet()
método genera el siguiente código de bytes:Y aquí está el código de bytes del
synchronizedBlockGet()
método:Una diferencia significativa entre el método sincronizado y el bloque es que, el bloqueo sincronizado generalmente reduce el alcance del bloqueo. Como el alcance del bloqueo es inversamente proporcional al rendimiento, siempre es mejor bloquear solo la sección crítica del código. Uno de los mejores ejemplos de uso de bloque sincronizado es el bloqueo doblemente verificado en el patrón Singleton, donde en lugar de bloquear todo
getInstance()
método solo bloqueamos la sección crítica del código que se usa para crear la instancia Singleton. Esto mejora drásticamente el rendimiento porque el bloqueo solo se requiere una o dos veces.Al utilizar métodos sincronizados, deberá tener especial cuidado si combina métodos sincronizados estáticos y no sincronizados.
fuente
monitorenter
ymonitorexit
antes de ejecutar el código.La mayoría de las veces lo uso para sincronizar el acceso a una lista o mapa, pero no quiero bloquear el acceso a todos los métodos del objeto.
En el siguiente código, un subproceso que modifica la lista no bloqueará la espera de un subproceso que esté modificando el mapa. Si los métodos estuvieran sincronizados en el objeto, entonces cada método tendría que esperar aunque las modificaciones que están haciendo no entren en conflicto.
fuente
Con los bloques sincronizados, puede tener múltiples sincronizadores, de modo que puedan ocurrir varias cosas simultáneas pero no conflictivas al mismo tiempo.
fuente
Los métodos sincronizados se pueden verificar utilizando la API de reflexión. Esto puede ser útil para probar algunos contratos, como todos los métodos en el modelo están sincronizados .
El siguiente fragmento imprime todos los métodos sincronizados de Hashtable:
fuente
Nota importante sobre el uso del bloque sincronizado: ¡cuidado con lo que usa como objeto de bloqueo!
El fragmento de código del usuario 2277816 anterior ilustra este punto en que se usa una referencia a un literal de cadena como objeto de bloqueo. Tenga en cuenta que los literales de cadena se internan automáticamente en Java y debe comenzar a ver el problema: ¡cada pieza de código que se sincroniza en el "bloqueo" literal comparte el mismo bloqueo! Esto puede conducir fácilmente a puntos muertos con piezas de código completamente no relacionadas.
No es solo con los objetos String con los que debes tener cuidado. Las primitivas en caja también son un peligro, ya que los métodos de autoboxing y valueOf pueden reutilizar los mismos objetos, dependiendo del valor.
Para obtener más información, consulte: https://www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused
fuente
A menudo, usar un candado en un nivel de método es demasiado grosero. ¿Por qué bloquear un fragmento de código que no accede a ningún recurso compartido al bloquear un método completo? Dado que cada objeto tiene un bloqueo, puede crear objetos ficticios para implementar la sincronización a nivel de bloque. El nivel de bloque es más eficiente porque no bloquea todo el método.
Aquí un ejemplo
Nivel de método
Nivel de bloque
[Editar]
Para me
Collection
gustaVector
yHashtable
se sincronizan cuandoArrayList
oHashMap
no, y necesita establecer una palabra clave sincronizada o invocar el método sincronizado de Colecciones:fuente
La única diferencia: los bloques sincronizados permiten el bloqueo granular a diferencia del método sincronizado
Básicamente
synchronized
, se han utilizado bloques o métodos para escribir código seguro para subprocesos evitando errores de inconsistencia de memoria.Esta pregunta es muy antigua y muchas cosas han cambiado durante los últimos 7 años. Se han introducido nuevas construcciones de programación para la seguridad del hilo.
Puede lograr la seguridad de subprocesos mediante el uso de API de concurrencia avanzada en lugar de
synchronied
bloques. Esta página de documentación proporciona buenas construcciones de programación para lograr la seguridad del subproceso.Los objetos de bloqueo admiten modismos de bloqueo que simplifican muchas aplicaciones concurrentes.
Los ejecutores definen una API de alto nivel para lanzar y administrar hilos. Las implementaciones de ejecutor proporcionadas por java.util.concurrent proporcionan una gestión de grupo de subprocesos adecuada para aplicaciones a gran escala.
Las Colecciones concurrentes facilitan la gestión de grandes colecciones de datos y pueden reducir en gran medida la necesidad de sincronización.
Las variables atómicas tienen características que minimizan la sincronización y ayudan a evitar errores de consistencia de la memoria.
ThreadLocalRandom (en JDK 7) proporciona una generación eficiente de números pseudoaleatorios a partir de múltiples hilos.
El mejor reemplazo para sincronizado es ReentrantLock , que usa
Lock
APIEjemplo con cerraduras:
Consulte los paquetes java.util.concurrent y java.util.concurrent.atomic también para otras construcciones de programación.
Consulte también esta pregunta relacionada:
Sincronización vs bloqueo
fuente
El método sincronizado se usa para bloquear todos los objetos El bloque sincronizado se usa para bloquear objetos específicos
fuente
En general, estos son en su mayoría los mismos, aparte de ser explícitos sobre el monitor del objeto que se está utilizando frente al implícito de este objeto. Una desventaja de los métodos sincronizados que creo que a veces se pasa por alto es que al usar la referencia "this" para sincronizar, está dejando abierta la posibilidad de que objetos externos se bloqueen en el mismo objeto. Eso puede ser un error muy sutil si te encuentras con él. La sincronización en un Objeto interno explícito u otro campo existente puede evitar este problema, encapsulando completamente la sincronización.
fuente
Como ya se dijo aquí, el bloque sincronizado puede usar una variable definida por el usuario como objeto de bloqueo, cuando la función sincronizada usa solo "esto". Y, por supuesto, puede manipular las áreas de su función que deben sincronizarse. Pero todos dicen que no hay diferencia entre la función sincronizada y el bloque que cubre la función completa usando "esto" como objeto de bloqueo. Eso no es cierto, la diferencia está en el código de bytes que se generará en ambas situaciones. En caso de uso de bloque sincronizado se debe asignar una variable local que contenga referencia a "esto". Y como resultado, tendremos un tamaño un poco más grande para la función (no es relevante si solo tiene un número reducido de funciones).
Explicación más detallada de la diferencia que puede encontrar aquí: http://www.artima.com/insidejvm/ed2/threadsynchP.html
fuente
En caso de métodos sincronizados, el bloqueo se adquirirá en un Objeto. Pero si utiliza el bloque sincronizado, tiene la opción de especificar un objeto en el que se adquirirá el bloqueo.
Ejemplo:
fuente
Sé que esta es una vieja pregunta, pero con mi lectura rápida de las respuestas aquí, realmente no vi a nadie mencionar que a veces un
synchronized
método puede ser el bloqueo incorrecto .De la concurrencia de Java en la práctica (pág. 72):
El código anterior tiene la apariencia de ser seguro para subprocesos. Sin embargo, en realidad no lo es. En este caso, el bloqueo se obtiene en la instancia de la clase. Sin embargo, es posible que la lista sea modificada por otro hilo que no use ese método. El enfoque correcto sería usar
El código anterior bloquearía todos los hilos que intentan modificar la lista para que no modifique la lista hasta que se complete el bloqueo sincronizado.
fuente
List
puede conducir a problemas de rendimiento si hay un registro de código que no necesariamente necesita sincronizarseComo cuestión práctica, la ventaja de los métodos sincronizados sobre los bloques sincronizados es que son más resistentes a los idiotas; debido a que no puede elegir un objeto arbitrario para bloquear, no puede usar incorrectamente la sintaxis del método sincronizado para hacer cosas estúpidas como bloquear un literal de cadena o bloquear el contenido de un campo mutable que se cambia desde debajo de los hilos.
Por otro lado, con los métodos sincronizados no puede proteger el bloqueo de cualquier subproceso que pueda obtener una referencia al objeto.
Por lo tanto, usar sincronizado como un modificador en los métodos es mejor para proteger a sus orcos de lastimarse a sí mismos, mientras que usar bloques sincronizados junto con objetos privados de bloqueo final es mejor para proteger su propio código de los orquineros.
fuente
De un resumen de especificaciones de Java: http://www.cs.cornell.edu/andru/javaspec/17.doc.html
En base a estas descripciones, diría que la mayoría de las respuestas anteriores son correctas, y un método sincronizado podría ser particularmente útil para métodos estáticos, donde de lo contrario tendría que descubrir cómo obtener el "Objeto de clase que representa la clase en la que se utilizó el método definido ".
Editar: originalmente pensé que estas eran citas de la especificación real de Java. Aclaró que esta página es solo un resumen / explicación de la especificación
fuente
TLDR; No utilice el
synchronized
modificador ni lasynchronized(this){...}
expresión, sinosynchronized(myLock){...}
dóndemyLock
es un campo de instancia final que contiene un objeto privado.La diferencia entre usar el
synchronized
modificador en la declaración del método y lasynchronized(..){ }
expresión en el cuerpo del método es la siguiente:synchronized
modificador especificado en la firma del método.synchronized(this) { .... }
, ythis
objeto como bloqueo cuando se declara en un método no estático o la clase adjunta cuando se declara en un método estático.synchronized(...){...}
expresión te permiteSin embargo, usar el
synchronized
modificador osynchronized(...) {...}
conthis
el objeto de bloqueo (como ensynchronized(this) {...}
) tiene la misma desventaja. Ambos usan su propia instancia como el objeto de bloqueo para sincronizar. Esto es peligroso porque no solo el objeto en sí, sino cualquier otro objeto / código externo que tenga una referencia a ese objeto también puede usarlo como un bloqueo de sincronización con efectos secundarios potencialmente graves (degradación del rendimiento y puntos muertos ).Por lo tanto, la mejor práctica es no usar el
synchronized
modificador ni lasynchronized(...)
expresión junto conthis
un objeto de bloqueo, sino un objeto de bloqueo privado para este objeto. Por ejemplo:También puede usar varios objetos de bloqueo, pero se debe tener especial cuidado para garantizar que esto no provoque bloqueos cuando se usa anidado.
fuente
Supongo que esta pregunta es sobre la diferencia entre Thread Safe Singleton y Lazy initialization with Double check lock . Siempre me refiero a este artículo cuando necesito implementar algún singleton específico.
Bueno, este es un Thread Safe Singleton :
Esta es una inicialización diferida con bloqueo de doble verificación :
Consulte este artículo para obtener más detalles:
https://www.geeksforgeeks.org/java-singleton-design-pattern-practices-examples/
fuente
Sincronización con hilos. 1) NUNCA use sincronizado (esto) en un hilo que no funciona. La sincronización con (esto) usa el hilo actual como el objeto de hilo de bloqueo. Dado que cada hilo es independiente de otros hilos, NO hay coordinación de sincronización. 2) Las pruebas de código muestran que en Java 1.6 en una Mac, la sincronización del método no funciona. 3) sincronizado (lockObj) donde lockObj es un objeto compartido común de todos los hilos que se sincronizarán en él. 4) ReenterantLock.lock () y .unlock () funcionan. Vea los tutoriales de Java para esto.
El siguiente código muestra estos puntos. También contiene el Vector seguro para subprocesos que sería sustituido por ArrayList, para mostrar que muchos subprocesos que se agregan a un Vector no pierden ninguna información, mientras que lo mismo con un ArrayList puede perder información. 0) El código actual muestra la pérdida de información debido a las condiciones de carrera A) Comente la línea A etiquetada actual, y elimine el comentario de la línea A por encima de ella, luego ejecute, el método pierde datos pero no debería. B) Invierta el paso A, descomente B y // bloque final}. Luego ejecute para ver resultados sin pérdida de datos C) Comente B, descomente C. Ejecute, vea que la sincronización en (esto) pierde datos, como se esperaba. No tengo tiempo para completar todas las variaciones, espero que esto ayude. Si la sincronización está activada (esto), o la sincronización del método funciona, indique qué versión de Java y sistema operativo ha probado. Gracias.
fuente