web-dev-qa-db-fra.com

Java méthode synchronisée

Considérons ce code:

public synchronized void onSignalsTimeout(List<SignalSpec> specs) {
    if (specs != null && specs.size() > 0) {
        for (SignalSpec spec : specs) {
            ParsedCANSignal timeoutedSignal = new ParsedCANSignal();
            SignalsProvider.getInstance().setSignal(spec.name, spec.parent.parent.channel, timeoutedSignal);
        }
    }
}

J'ai une question simple: lorsque le thread 1 appelle la méthode onSignalsTimeout, le thread 2 peut-il accéder aux objets auxquels on accède via cette méthode?

Impossible de trouver n'importe où si "synchronisé" verrouille uniquement l'accès à cette méthode ou à tous les objets utilisés dans cette méthode.

36
arenaq

Tout d’abord, oubliez Synchronisé méthodes. Une méthode dite synchronisée ...

synchronized AnyType foobar(...) {
    doSomething();
}

N’est qu’un raccourci pour écrire ceci:

AnyType foobar(...) {
    synchronized(this) {
        doSomething();
    }
}

Il n'y a rien de spécial à propos de méthode dans les deux cas. Ce qui est spécial est le synchronized block, et ce qu'un bloc synchronisé fait est très simple. Lorsque la machine virtuelle exécute ceci:

synchronized(foo) {
    doSomething();
}

Il évalue d’abord l’expression foo. Le résultat doit être une référence d'objet. Ensuite, il verrouille l'objet, exécute le corps du bloc synchronized, puis déverrouille l'objet.

Mais que signifie verrouillé? Cela peut vouloir dire moins que vous ne le pensez. Cela not empêche les autres threads d'utiliser l'objet. Cela ne les empêche pas d'accéder aux champs de l'objet ou de mettre à jour ses champs. La seule chose que le verrouillage d'un objet empêche, c'est d'empêcher d'autres threads de verrouiller le même objet en même temps.

Si le thread A tente d'entrer synchronized(foo) {...} alors que le thread B est déjà verrouillé (soit dans le même bloc synchronized, soit dans un bloc différent), le thread A sera forcé d'attendre que thread B libère le verrou.


Vous utilisez synchronized des blocs pour protéger data.

Supposons que votre programme possède une collection d'objets pouvant être dans différents états. Supposons que certains états aient un sens, mais qu'il y en ait d'autres qui n'ont pas de sens —invalide états.

Supposons qu’un thread ne puisse pas changer les données d’un état valide à un autre état valide sans temporairement créer un état non valide.

Si vous mettez le code qui modifie l'état dans un bloc synchronized(foo), et que vous mettez tous bloc de code pouvant voir l'état dans un bloc synchronisé qui verrouille le même objet, foo, vous empêcherez alors les autres threads de voir l'état temporairement invalide.

92
Solomon Slow

Oui, d'autres threads peuvent accéder aux objets utilisés dans la méthode. le mot clé synchronized garantit que pas plus d'un thread à la fois ne peut exécuter le code de la méthode.

De https://docs.Oracle.com/javase/tutorial/essential/concurrency/syncmeth.html :

  • Premièrement, 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 invoquent des méthodes synchronisées pour le même bloc d'objet (suspendre l'exécution) jusqu'à la fin du premier thread avec l'objet.
  • Deuxièmement, lorsqu'une méthode synchronisée se termine, elle établit automatiquement une relation passe-avant avec tout appel ultérieur d'une méthode synchronisée pour le même objet. Cela garantit que les modifications apportées à l'état de l'objet sont visibles par tous les threads. Notez que les constructeurs ne peuvent pas être synchronisés - l'utilisation du mot clé synchronized avec un constructeur est une erreur de syntaxe. Synchroniser les constructeurs n'a pas de sens, car seul le thread qui crée un objet doit y avoir accès pendant sa construction.
8
Andrea Iacono

Dans ce contexte, synchronized verrouille simultanément cette méthode et toute autre méthode portant le même identificateur synchronized dans votre classe.

5
Bathsheba