web-dev-qa-db-fra.com

Deux méthodes synchronisées s'exécutent-elles simultanément

J'ai 4 méthodes (m1, m2, m3 et m4) dans une classe. Les méthodes m1, m2 et m3 sont des méthodes synchronized. En outre, j'ai 4 threads t1, t2, t3 et t4 respectivement.

Si t1 accède à la méthode m1 (méthode synchronisée), t2 pourrait-il accéder simultanément à la méthode m2 (méthode synchronisée)? Si non, quel serait l'état de t2?

31
Tony

Si t1 accède à la méthode m1 (méthode synchronisée), le processus t2 peut-il accéder à la méthode m2 (méthode synchronisée) simultanément?

Le mot clé synchronized s'applique au niveau de l'objet} et un seul thread peut conserver le verrou de l'objet. Donc, tant que vous parlez du même objet, alors no , t2 attendra que t1 libère le verrou acquis lors de la saisie de m1.

Le thread peut toutefois libérer le verrou sans revenir de la méthode en appelant Object.wait().

Si non, quel serait l'état de t2?

Il resterait bien en place et attendrait que t1 libère le verrou (revenez de la méthode ou appelez Object.wait()). Spécifiquement, il sera dans un état BLOCKED .

Etat d'un thread bloqué en attente d'un verrou de moniteur. Un thread bloqué attend qu'un verrou de moniteur entre un bloc/une méthode synchronisé ou ressaisisse un bloc/une méthode synchronisé après avoir appelé Object.wait. 

Exemple de code:

public class Test {

    public synchronized void m1() {
        try { Thread.sleep(2000); }
        catch (InterruptedException ie) {}
    }

    public synchronized void m2() {
        try { Thread.sleep(2000); }
        catch (InterruptedException ie) {}
    }

    public static void main(String[] args) throws InterruptedException {
        final Test t = new Test();
        Thread t1 = new Thread() { public void run() { t.m1(); } };
        Thread t2 = new Thread() { public void run() { t.m2(); } };

        t1.start();
        Thread.sleep(500);

        t2.start();
        Thread.sleep(500);

        System.out.println(t2.getState());
    }
}

Sortie:

BLOCKED
44
aioobe

Si les méthodes sont synchronisées sur le même moniteur, elles ne peuvent pas s'exécuter simultanément dans différents threads. Lorsque le deuxième thread arrive à l'entrée du moniteur (le début de la méthode synchronisée dans ce cas), il se bloque jusqu'à ce que le premier thread libère le moniteur.

Dans ce cas, l’état actuel du thread bloqué, comme indiqué par jconsole, sera quelque chose comme Java.lang.Thread.State: WAITING (on object monitor)

En supposant que toutes les méthodes sont des méthodes d'instance normales, elles partageront le même moniteur lorsqu'elles sont invoquées sur le même objet . Autrement dit, si vous aviez quelque chose comme:

// Thread 1
A a1 = new A();
a1.m1();

// Thread 2
A a2 = new A();
a2.m2()

alors, dans ce cas, le second thread pourra appeler la méthode, car il tente d'obtenir le moniteur implicite de l'objet a2, qui est not verrouillé par le thread 1. Toutefois, si le thread 2 tente d'appeler a1.m2(), alors il serait bloqué jusqu'à ce que le thread 1 ait fini d'exécuter m1().

Si vous avez des méthodes statiques, ils obtiennent le moniteur explicite de la classe elle-même (A.class dans mon cas de nommage hypothétique), ils ne seront donc pas bloqués par les invocations de méthodes any instance.

11
Andrzej Doyle

Non, ça ne pouvait pas. C'est le seul point qu'il y a à synchronized: différents threads ne peuvent pas faire ces choses simultanément (vous n'avez pas à vous protéger contre le même thread en les faisant simultanément, car un seul thread ne peut rien faire en parallèle du tout.) l'état du thread en attente est 'en attente de verrouillage'. (Avec une JVM suffisamment moderne, vous pouvez réellement afficher cet état sur la console si vous le demandez correctement.)

4
Kilian Foth

Si t1 accède à la méthode m1 (méthode synchronisée), le processus t2 peut-il accéder à la méthode m2 (méthode synchronisée) simultanément?

No. Thread t2 attendra que Thread t1 lâche le verrou. Dans votre même exemple, t2 peut accéder à la méthode m4 qui n’est pas synchronisée.

Verrous/ synchronisé Méthodes

Chaque objet est associé à un verrou intrinsèque. Par convention, un thread qui nécessite un accès exclusif et cohérent aux champs d'un objet doit acquérir le verrou intrinsèque de l'objet avant d'y accéder, puis libérer le verrou intrinsèque lorsqu'il en a terminé avec eux.

Lorsqu'un thread appelle une méthode synchronisée, il acquiert automatiquement le verrou intrinsèque pour l'objet de cette méthode et le libère au retour de la méthode. Le déverrouillage se produit même si le retour a été provoqué par une exception non interceptée

Revenons à votre deuxième requête:

Si non, quel serait l'état de t2?

Le thread t2 est bloqué et attend que le thread t1 relâche le verrou.

Depuis Java documentation page:

rendre la méthode synchronized a deux effets.

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.

1
Aditya W