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?

jbu
la source

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. :)

OscarRyz
la source
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é.

Cowan
la source
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.

jfpoilpret
la source
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).

essayer-attraper-enfin
la source
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 .

Ravindra babu
la source
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

Pahansith Gunathilake
la source
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
Ravi
la source
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.

Pragya
la source