Si un método sincronizado llama a otro método sincronizado, ¿es seguro para subprocesos?
void synchronized method1() {
method2()
}
void synchronized method2() {
}
Si un método sincronizado llama a otro método sincronizado, ¿es seguro para subprocesos?
void synchronized method1() {
method2()
}
void synchronized method2() {
}
Respuestas:
Sí, cuando marca métodos como synchronized
, realmente está haciendo esto:
void method1() {
synchronized (this) {
method2()
}
}
void method2() {
synchronized (this) {
}
}
Cuando la llamada al hilo ingresa al método2 desde el método1, entonces se asegurará de que mantiene el bloqueo this
, lo cual ya lo hará, y luego puede pasar.
Cuando el hilo entra directamente en el método1 o el método2, entonces se bloqueará hasta que pueda obtener el bloqueo ( this
), y luego entrará.
Como señaló James Black en los comentarios, debe ser consciente de lo que hace dentro del cuerpo del método.
private final List<T> data = new ArrayList<T>();
public synchronized void method1() {
for (T item : data) {
// ..
}
}
public void method3() {
data.clear();
}
De repente, no es seguro para subprocesos porque está mirando a ConcurrentModificationException
en su futuro porque method3
no está sincronizado y, por lo tanto, podría ser llamado por Thread A mientras Thread B está funcionando method1
.
method3
muestra operaciones de subprocesamiento inseguras, pero estás acertado sobre la sincronización reentrante.
Es un método marcado con llamada sincronizada, otro método sincronizado seguro para subprocesos.
En general, no es posible decirlo. Depende de lo que hagan los métodos y de lo que hagan otros métodos en la misma y en otras clases.
Sin embargo, podemos estar seguros de que las llamadas al método1 y al método2 en el mismo objeto realizadas por diferentes subprocesos no se ejecutarán simultáneamente. Dependiendo de lo que hagan los métodos, esto puede ser suficiente para decir que la clase es segura para subprocesos con respecto a estos métodos.
Desde el sitio de tutoriales de Java http://download.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
No es posible que se intercalen dos invocaciones de métodos sincronizados en el mismo objeto. Cuando un subproceso está ejecutando un método sincronizado para un objeto, todos los demás subprocesos que invocan métodos sincronizados para el mismo bloque de objetos (suspenden la ejecución) hasta que el primer subproceso finaliza con el objeto.
cuando un método sincronizado sale, automáticamente establece una relación de suceder antes 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.
Por lo tanto, Java se asegurará de que si 2 subprocesos están ejecutando el mismo método, los métodos no se ejecutarán de forma simultánea, sino uno tras otro.
Pero debe ser consciente del problema de Liveness, http://download.oracle.com/javase/tutorial/essential/concurrency/starvelive.html
Y también si está bloqueando innecesariamente, porque en el código que usó esto , que bloquea todo el objeto, si su objeto solo necesita acceso de sincronización a una variable, debe bloquear esa variable.
synchronized (this.someVar)
que estás mirando el objeto cuya referencia se mantiene someVar
. La distinción es muy importante.