2010-12-04 11 views
10

En un programa Java altamente concurrente y suponiendo que mis métodos están escritos correctamente y correctamente sincronizados, me pregunto acerca de cómo determinar qué es mejor:Costo de sincronización

void synchronized something() { 
    ... 
} 

o

void something() { 
    synchronized(this) { 
     ... 
    } 
    // here do stuff no requiring synchronization 
    . 
    . // do computation 'A' 
    . 
    synchronized(this) { 
     ... 
    } 
    // here do other stuff no requiring synchronization 
    . 
    . // do computation 'B' 
    . 
    synchronized(this) { 
     ... 
    } 
} 

Ahora me doy cuenta de que si los cálculos 'A' y 'B' toman mucho tiempo, la segunda versión es obviamente mejor.

Mi pregunta, sin embargo, es: ¿en qué momento sabe usted que la segunda versión es más eficiente?

¿La segunda versión es siempre más rápida o hay un costo oculto por adquirir/liberar la cerradura varias veces?

Qué pasa si mi cálculo 'A' es simplemente algo trivial como:

s.getString().substring(0, 2).toLowerCase(); 
+0

tenga en cuenta que tengo mi copia de * "Java Concurrency in Practice" * :) – SyntaxT3rr0r

Respuesta

8

Sí, synchronized cuesta tiempo. Si los cálculos reales son simples y están dentro de un bucle o más, cuesta lotes de tiempo en comparación con los cálculos reales.

Vea este ejemplo: http://ideone.com/zgpB7

  • parte interior sincronizado: aproximadamente 0.025s
  • bucle entero sincronizado: menos de 0,001 s

Para determinar cuál es mejor para su programa, vamos realiza cosas y mira en qué momento es más rápido.

+0

+1 ... Estoy bastante sorprendido :) Estaba casi seguro de que había algo más que lo que se ve :) – SyntaxT3rr0r

+5

La otra cosa que muestra ese ejemplo es que 1,000,000 bloqueos de sincronización toman 0.024 segundos. Entonces, a menos que esté iterando millones de veces, o tenga una contención de recursos provable entre hilos, la sincronización en sí misma no es tan lenta. (aparentemente 0.000000024 segundos por cerradura en la máquina que ejecuta esos ejemplos). – Gus

+1

Creo que el mayor golpe al uso de grandes bloques sincronizados es la pérdida de concurrencia. De repente, tus múltiples procesadores no ayudan. Si tiene otros hilos que no están esperando en el candado, puede que no sea tan malo, aunque – Cruncher

2

thejh hace una buena idea de que hay algún costo para bloquear repetidamente un hilo. Sin embargo, cada vez que he hablado con personas acerca de los hilos paralelos, siempre ha sido para asegurarme de que todos los hilos se ejecutan rápidamente cuando se ejecutan al mismo tiempo.

Mantener un bloqueo durante más tiempo de lo necesario puede ralentizar los otros hilos. Deben sentarse y esperar mientras haces un trabajo que no interfiera con el trabajo que quieren hacer. Si esta es una situación en la que realmente le importan los milisegundos, debe usar un generador de perfiles para ver qué funciona mejor dada su situación. La optimización multithreading es una de esas situaciones en las que hay "mejores prácticas" que generalmente son ciertas, pero no se obtendrá una regla que funcione en todas las situaciones. Si necesita mucha granularidad, debe probarla y ver.

1

¿"correctamente escrito" y "correctamente sincronizado" significa que no hay dependencias entre las secciones de código en el caso de sincronización múltiple? Si hay dependencias, entonces podría ser que el caso multi-sincronizado podría resultar en la violación de un invariante. Dicho de otra manera, ¿puede garantizar que la ejecución del caso multisincronizado no dará lugar a que algún objeto se encuentre en un estado no válido? Si no, entonces el caso de sincronización simple podría ser mejor.

+0

sí, está garantizado. Esa es precisamente la premisa de mi pregunta :) IOW, puede ver mi pregunta como una pregunta puramente teórica :) – SyntaxT3rr0r

+1

@SpoonBender: En ese caso, el rendimiento relativo de las dos soluciones podría depender de la cantidad de CPU-s disponibles. –

+0

@SteveEmmerson o una función de la relación entre el número de subprocesos y las CPU. – Cruncher