web-dev-qa-db-fra.com

Est-il sûr d'appeler une méthode synchronisée à partir d'une autre méthode synchronisée?

Si une méthode synchronisée appelle une autre méthode synchronisée, est-elle sécurisée pour les threads?

void synchronized method1() {
     method2()
}

void synchronized method2() {
}
76
user705414

Oui, lorsque vous marquez des méthodes comme synchronized, alors vous faites vraiment ceci:

void method1() {
    synchronized (this) {
        method2()
    }
}

void method2() {
    synchronized (this) {
    }
}

Lorsque l'appel de thread entre dans method2 à partir de method1, il s'assurera qu'il détient le verrou sur this, ce qu'il sera déjà, puis il pourra passer.

Lorsque le thread entre directement dans method1 ou method2, il se bloque jusqu'à ce qu'il puisse obtenir le verrou (this), puis il entre.

Comme indiqué par James Black dans les commentaires, vous devez être conscient de ce que vous faites à l'intérieur du corps de la méthode.

private final List<T> data = new ArrayList<T>();

public synchronized void method1() {
    for (T item : data) {
        // ..
    }
}

public void method3() {
    data.clear();
}

Du coup, ce n'est pas sûr pour les threads car vous regardez un ConcurrentModificationException dans votre futur parce que method3 n'est pas synchronisé et peut donc être appelé par le thread A pendant que le thread B travaille dans method1.

97
pickypg

Est une méthode marquée par appel synchronisé, un autre thread sécurisé de méthode synchronisée.

En général, il n'est pas possible de le dire. Cela dépend de ce que font les méthodes et de ce que font les autres méthodes de la même classe et des autres classes.

Cependant, nous pouvons être sûrs que les appels à method1 et method2 sur le même objet effectués par des threads différents ne s'exécuteront pas simultanément. Selon ce que font les méthodes, cela peut être suffisant pour dire que la classe est thread-safe par rapport à ces méthodes.

5
Stephen C

Depuis le site Java Tutorials http://download.Oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

  1. Il n'est pas possible que deux invocations de méthodes synchronisées sur le même objet s'entrelacent. Lorsqu'un thread exécute une méthode synchronisée pour un objet, tous les autres threads qui appellent des méthodes synchronisées pour le même bloc d'objet (suspendent l'exécution) jusqu'à ce que le premier thread soit terminé avec l'objet.

  2. lorsqu'une méthode synchronisée se termine, elle établit automatiquement une relation passe-avant avec toute invocation ultérieure d'une méthode synchronisée pour le même objet. Cela garantit que les modifications de l'état de l'objet sont visibles pour tous les threads

Donc Java garantira que si 2 threads exécutent la même méthode, les méthodes ne seront pas exécutées simultanément mais l'une après l'autre.

Mais vous devez être conscient du problème de Liveness, http://download.Oracle.com/javase/tutorial/essential/concurrency/starvelive.html

Et aussi si vous vous verrouillez sans nécessité, cause dans le code que vous avez utilisé ceci , qui verrouille l'objet entier, si votre objet n'a besoin que d'un accès synchronisé à une variable vous devez simplement verrouiller cette variable.

1
Stephen Lee