swimming - ¿Por qué la sincronización es cara en Java?
synchronized(object) java (5)
Soy realmente nuevo en Java y leí que "sincronizado" es "muy caro" en Java. Todo lo que quiero saber es qué es caro y cómo es caro. Gracias.
Es costoso porque si está utilizando subprocesos, y varios subprocesos tienen que pasar por una sección de código sincronizada, solo uno de ellos puede ejecutarse a la vez.
Es como un cuello de botella.
Incluso es caro cuando se usa un solo hilo, porque tiene que verificar de todos modos si se le permite correr.
Si reduce el uso de segmentos sincronizados, su hilo no tendrá que detenerse para ver si pueden ejecutarse (por supuesto, no tienen que compartir datos)
Una descripción general de alto nivel de cómo funciona la sincronización se puede encontrar here
http://img20.imageshack.us/img20/2066/monitor28synchronizatioc.png
Un monitor de estilo Java
Este Here sobre IBM en realidad resume muy bien los puntos principales detrás de la sincronización.
Debido a las reglas que implican el vaciado y la invalidación de la memoria caché, un bloque sincronizado en el lenguaje Java es generalmente más costoso que las facilidades de la sección crítica ofrecidas por muchas plataformas, que generalmente se implementan con una instrucción de máquina atómica de "prueba y conjunto de bits". Incluso cuando un programa contiene un solo subproceso que se ejecuta en un solo procesador, una llamada a un método sincronizado sigue siendo más lenta que una llamada a un método no sincronizado. Si la sincronización realmente requiere una disputa por el bloqueo, la penalización de rendimiento es sustancialmente mayor, ya que habrá varios cambios de subprocesos y se requerirán llamadas al sistema.
Esto no es tan específico de Java. La sincronización puede considerarse "cara" en cualquier entorno de subprocesos múltiples si no se realiza correctamente. Si es particularmente malo en Java, no lo sé.
Evita que las hebras se ejecuten simultáneamente si usan el mismo recurso. Pero, como usan el mismo recurso, no hay mejor opción (hay que hacerlo).
El problema es que las personas a menudo protegen un recurso con un alcance demasiado grande. Por ejemplo, un programa mal diseñado puede sincronizar una matriz completa de objetos en lugar de cada elemento individual de la matriz (o incluso una sección de la matriz).
Esto significaría que un subproceso que intenta leer el elemento 7 debe esperar a que un subproceso lea o escriba el elemento 22. No es necesario. Si la granularidad de la sincronización estuviera en el nivel de elemento en lugar del nivel de matriz, esos dos hilos no interferirían entre sí.
Solo cuando dos subprocesos intentaron acceder al mismo elemento habría contención de recursos. Es por eso que la regla general es proteger un recurso tan pequeño como sea posible (sujeto a limitaciones en el número de sincronizaciones, por supuesto).
Pero, para ser honesto, no importa lo costoso que sea si la alternativa es la corrupción de datos debido a dos subprocesos que luchan por un solo recurso. Escriba su aplicación correctamente y solo se preocupe por los problemas de rendimiento cuando aparezcan ("Consiga que funcione primero y luego que funcione rápido" es mi mantra favorito).
Las otras respuestas proporcionan un buen nivel de detalles técnicos que no voy a intentar replicar.
Lo que haré es aconsejarle que verifique las fechas de los artículos (así como la competencia y conocimiento implícitos del autor). La sincronización en Java fue muy lenta en las JVM anteriores. Sin embargo, ha mejorado mucho recientemente, de modo que la sincronización incontenida es mucho más rápida de lo que podría pensar, y la sincronización incontenida también ha mejorado.
Eso sí, esta pregunta posiblemente no importa: si necesita sincronizar para garantizar la corrección, debe sincronizar para garantizar la corrección. Las únicas veces que veo que la velocidad es un problema es si estaba considerando crear una implementación sin bloqueo en su lugar (utilizando el muy eficiente pero complejo java.util.concurrent.locks.AbstractQueuedSynchronizer ), o tal vez considerando usar otro idioma para su tarea.
En general, creo que la mejor conclusión es que la sincronización es generalmente lo suficientemente rápida como para usarla en una primera iteración. Al igual que con todas las preocupaciones de rendimiento, codifique la claridad y la corrección al principio y luego solo optimice lo que mide para que sea una parte costosa de su aplicación. Normalmente, este no será el costo de la sincronización *.
Tal vez no sea tan malo como crees
Solía ser terrible (que posiblemente sea la razón por la que leíste que era "muy caro"). Estos memes pueden tardar mucho tiempo en extinguirse.
Here hay un buen artículo al respecto.
¿Qué tan caro es la sincronización?
Debido a las reglas que implican el vaciado y la invalidación de la memoria caché, un bloque sincronizado en el lenguaje Java es generalmente más costoso que las facilidades de la sección crítica ofrecidas por muchas plataformas, que generalmente se implementan con una instrucción de máquina atómica de "prueba y configuración". Incluso cuando un programa contiene un solo subproceso que se ejecuta en un solo procesador, una llamada a un método sincronizado sigue siendo más lenta que una llamada a un método no sincronizado. Si la sincronización realmente requiere una disputa por el bloqueo, la penalización de rendimiento es sustancialmente mayor, ya que habrá varios cambios de subprocesos y se requerirán llamadas al sistema.
Afortunadamente, las mejoras continuas en la JVM mejoraron el rendimiento general del programa Java y redujeron el costo relativo de la sincronización con cada versión, y se anticipan mejoras futuras. Además, los costos de rendimiento de la sincronización a menudo son exagerados. Una fuente bien conocida ha citado que una llamada a un método sincronizado es hasta 50 veces más lenta que una llamada a un método no sincronizado. Si bien esta afirmación puede ser cierta, también es bastante engañosa y ha llevado a muchos desarrolladores a evitar la sincronización, incluso en los casos en que se necesita.
Habiendo dicho eso, la programación concurrente aún puede ser lenta, pero no tanto es solo culpa de Java ahora. Hay un intercambio entre el bloqueo fino y grueso. Demasiado burdo es obviamente malo, pero también es posible que sea demasiado fino, ya que los bloqueos no tienen un costo de cero.
Es importante considerar el recurso particular bajo disputa. Los discos duros mecánicos son un ejemplo en el que más hilos pueden llevar a un peor rendimiento.