Méthodes statiques synchronisées Java: verrouillage sur un objet ou une classe


148

La documentation Java dit:

Il n'est pas possible que deux invocations de méthodes synchronisées sur le même objet s'entrelacent.

Qu'est-ce que cela signifie pour une méthode statique? Puisqu'une méthode statique n'a pas d'objet associé, le mot clé synchronisé se verrouille-t-il sur la classe au lieu de l'objet?

Réponses:


129

Puisqu'une méthode statique n'a pas d'objet associé, le mot clé synchronisé se verrouille-t-il sur la classe au lieu de l'objet?

Oui. :)


81
Veuillez répondre Elaborate afin que tout le monde puisse comprendre.
Madhu

6
@Madhu. Cela signifie que si vous avez 2 méthodes synchronisées ou plus sur la même classe, les deux ne peuvent pas s'exécuter en même temps, même s'il existe plusieurs instances de cette classe. Le verrouillage est essentiellement le même que le verrouillage sur Object.class pour chaque méthode synchronisée.
Steven

Cette réponse est erronée - thisle verrou est-il acquis sur les méthodes d'instance -, veuillez le réparer Oscar.
vemv

1
@vemv La question concerne les méthodes de classe, pas les méthodes d'instance.
OscarRyz

23
@vemv Eh bien oui, pour comprendre la réponse, vous devez d'abord lire la question.
OscarRyz

199

Juste pour ajouter un petit détail à la réponse d'Oscar (agréablement succincte!), La section pertinente sur la spécification du langage Java est 8.4.3.6, `` Méthodes synchronisées '' :

Une méthode synchronisée acquiert un moniteur ( §17.1 ) avant son exécution. Pour une méthode de classe (statique), le moniteur associé à l'objet Class pour la classe de la méthode est utilisé. Pour une méthode d'instance, le moniteur associé à this (l'objet pour lequel la méthode a été appelée) est utilisé.


17
Utile, je cherchais cette citation +1
OscarRyz

80

Un point auquel vous devez faire attention (plusieurs programmeurs tombent généralement dans ce piège) est qu'il n'y a aucun lien entre les méthodes statiques synchronisées et les méthodes non statiques synchronisées, c'est-à-dire:

class A {
    static synchronized f() {...}
    synchronized g() {...}
}

Principale:

A a = new A();

Fil 1:

A.f();

Fil 2:

a.g();

f () et g () ne sont pas synchronisés l'un avec l'autre et peuvent donc s'exécuter totalement simultanément.


18
mais que se passe-t-il si g () mute une variable statique que f () lit. Comment sécuriser ce fil? Acquérons-nous alors explicitement un verrou sur la classe?
baskin

22
Oui, votre méthode non statique doit se synchroniser explicitement sur la classe elle-même (c.-à-d synchronized (MyClass.class) {...}.
jfpoilpret

@jfpoilpret "synchronized (MyClass.class) {...}" équivaut à rendre cette méthode statique synchronisée, non?
crazymind

15

Sauf si vous implémentez g () comme suit:

g() {
    synchronized(getClass()) {
        ...
    }
}

Je trouve ce modèle utile également lorsque je souhaite implémenter une exclusion mutuelle entre différentes instances de l'objet (ce qui est nécessaire lors de l'accès à une ressource externe, par exemple).


63
Notez qu'il peut en fait y avoir une chance de quelques bugs très subtils et méchants ici. Remember getClass()renvoie le type d' exécution ; si vous sous-classez la classe, la classe parente et la classe enfant se synchroniseront sur des verrous différents. synchronized(MyClass.class)est la voie à suivre si vous devez vous assurer que toutes les instances utilisent le même verrou.
Cowan

4

Consultez la page de documentation d'Oracle sur les verrous intrinsèques et la synchronisation

Vous pouvez vous demander ce qui se passe lorsqu'une méthode statique synchronisée est appelée, puisqu'une méthode statique est associée à une classe et non à un objet. Dans ce cas, le thread acquiert le verrou intrinsèque pour l'objet Class associé à la classe . Ainsi, l'accès aux champs statiques de la classe est contrôlé par un verrou distinct du verrou pour toute instance de la classe .


2

Une méthode statique a également un objet associé. Il appartient au fichier Class.class dans la boîte à outils JDK. Lorsque le fichier .class est chargé dans la mémoire vive, le Class.class en crée une instance appelée objet modèle.

Par exemple: - lorsque vous essayez de créer un objet à partir d'une classe client existante comme

Customer c = new Customer();

Le chargement de Customer.class dans la RAM. À ce moment-là, Class.class dans la boîte à outils JDK crée un objet appelé objet Template et charge ce Customer.class dans cet objet template. Les membres statiques de ce Customer.class deviennent des attributs et des méthodes dans cet objet template.

Ainsi, une méthode ou un attribut statique a également un objet


2

Les exemples ci-dessous donnent plus de clarté entre le verrouillage de classe et d'objet, espérons que l'exemple ci-dessous aidera également les autres :)

Par exemple, nous avons ci-dessous des méthodes une acquéreur de classe et une autre acquisition d'objet verrou:

public class MultiThread {

    public static synchronized void staticLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }

    public synchronized void objLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

Donc, maintenant, nous pouvons avoir les scénarios suivants:

  1. Lorsque les threads en utilisant un même objet tente d'accéder objLock OU staticLock méthode même temps ( les deux threads tentent d'accéder à même méthode)

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
  2. Lorsque les threads utilisant le même objet essaient d'accéder aux méthodes staticLocket en objLockmême temps (essaie d'accéder à différentes méthodes)

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
  3. Lorsque des threads utilisant un objet différent essaient d'accéder à la staticLockméthode

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
  4. Lorsque des threads utilisant un objet différent essaient d'accéder à la objLockméthode

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4

0

Pour ceux qui ne sont pas familiers avec la méthode statique synchronisée verrouillée sur un objet de classe, par exemple pour la classe string sa String.class tandis que la méthode synchronisée par instance se verrouille sur l'instance actuelle d'Objet désignée par le mot-clé «this» en Java. Étant donné que ces deux objets sont différents, ils ont un verrou différent.Ainsi, pendant qu'un thread exécute une méthode statique synchronisée, un autre thread en java n'a pas besoin d'attendre le retour de ce thread à la place, il acquiert un verrou séparé noté octet .class littéral et entre dans méthode statique synchronisée.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.