web-dev-qa-db-fra.com

Objet de verrouillage statique ou non statique dans un bloc synchronisé

Essayer de visualiser et de comprendre synchronisation.

  1. Quelles sont les différences entre l'utilisation d'un objet de verrouillage statique (code A) et a objet de verrouillage non statique (code B) pour a = bloc synchronisé?
  2. En quoi diffère-t-il dans les applications pratiques?
  3. Quels sont les pièges que l'un aurait que l'autre n'aurait pas?
  4. Quels sont les critères pour déterminer lequel utiliser?

Code A

public class MyClass1 {
  private static final Object lock = new Object();
  public MyClass1() {
    //unsync
    synchronized(lock) {
      //sync
    }
    //unsync
  }
}

Code B

public class MyClass2 {
  private final Object lock = new Object();
  public MyClass2() {
    //unsync
    synchronized(lock) {
      //sync
    }
    //unsync
  }
}

Remarque

Le code ci-dessus montre les constructeurs, mais vous pouvez aussi expliquer en quoi le comportement est différent dans une méthode statique et une méthode non statique. Serait-il également avantageux d'utiliser un verrou statique lorsque le bloc synchronisé modifie une variable membre statique?

J'ai déjà regardé les réponses dans cette question , mais ce n'est pas assez clair quels sont les différents scénarios d'utilisation.

36
ADTC

La différence est simple: si l'objet verrouillé se trouve dans un champ static, alors toutes les instances de MyClass*partager ce verrou (c'est-à-dire qu'il n'y aura pas deux objets capable de verrouiller cet objet en même temps).

Si le champ n'est pas statique, chaque instance aura son propre verrou, donc seuls les appels de la méthode sur le même objet se verrouillent mutuellement.

Lorsque vous utilisez un objet de verrouillage statique:

  • thread 1 appelle o1.foo()
  • le thread 2 appelle o1.foo(), devra attendre que le thread 1 se termine
  • le thread 3 appelle o2.foo(), aussi devra attendre que le thread 1 (et probablement 2) se termine

Lorsque vous utilisez un objet de verrouillage non statique:

  • thread 1 appelle o1.foo()
  • le thread 2 appelle o1.foo(), devra attendre que le thread 1 se termine
  • le thread 3 appelle o2.foo(), il peut simplement continuer, sans se soucier des threads 1 et 2

Lequel de ceux dont vous aurez besoin dépend du type de données que vous essayez de protéger avec votre bloc synchronisé.

En règle générale, vous voulez que le verrou-objet ait la même static- ness que la valeur opérée. Donc, si vous manipulez des valeurs non statiques niquement, vous aurez besoin d'un objet de verrouillage non statique. Si vous manipulez des valeurs statiques niquement, vous aurez besoin d'un objet de verrouillage statique.

Lorsque vous manipulez des valeurs statiques et non statiques, cela devient compliqué. La manière facile serait d'utiliser simplement un objet de verrouillage statique, mais cela pourrait augmenter la taille du bloc synchronisé plus qu'absolument nécessaire et pourrait nécessiter plus de conflits de verrouillage que souhaité. Dans ces cas, vous pourriez avoir besoin d'une combinaison d'objets de verrouillage statiques et non statiques.

Dans votre cas particulier, vous utilisez le verrou dans le constructeur, qui ne sera exécuté qu'une seule fois par instance, donc un objet de verrouillage non statique n'a aucun sens ici.

49
Joachim Sauer