75 votes

Dans les sections critiques Java, sur quoi dois-je synchroniser?

En Java, le moyen idiomatique de déclarer des sections critiques dans le code est le suivant:

 private void doSomething() {
  // thread-safe code
  synchronized(this) {
    // thread-unsafe code
  }
  // thread-safe code
}
 

Presque tous les blocs se synchronisent sur this , mais y a-t-il une raison particulière à cela? Y a-t-il d'autres possibilités? Existe-t-il des meilleures pratiques sur quel objet sur lequel se synchroniser? (comme des instances privées de Object ?)

72voto

Jared Points 7800

Comme précédemment answerers l'ont noté, il est de bonne pratique pour se synchroniser sur un objet de portée limitée (en d'autres termes, choisir le plus restrictive de la portée vous pouvez sortir avec, et de l'utiliser.) En particulier, la synchronisation sur l' this est une mauvaise idée, sauf si vous avez l'intention de permettre aux utilisateurs de votre classe pour obtenir le verrou.

Particulièrement laid cas, cependant, si vous choisissez de synchroniser sur un java.lang.String. Les chaînes peuvent être (et, dans la pratique, presque toujours) internés. Cela signifie que chaque chaîne de l'égalité contenu dans l' ENSEMBLE de la JVM s'avère être la même corde, derrière les coulisses. Cela signifie que si vous synchroniser sur toute la Chaîne, de l'autre (complètement disparates) section de code qui bloque sur une Chaîne avec le même contenu, verrouiller votre code.

J'ai été une fois dépannage d'une impasse dans un système de production et de (très douloureuse) suivi de l'impasse à deux complètement disparates packages open source que chaque synchronisé sur une instance de la Chaîne dont le contenu a été à la fois "LOCK".

51voto

Yuval Adam Points 59423

Tout d'abord, notez que les extraits de code suivants sont identiques.

public void foo() {
    synchronized (this) {
        // do something thread-safe
    }
}

et:

public synchronized void foo() {
    // do something thread-safe
}

faire exactement la même chose. Pas de préférence pour l'un d'eux, sauf pour la lisibilité du code et de style.

Lorsque vous ne synchroniser des méthodes ou des blocs de code, il est important de savoir pourquoi vous faites telle chose, et ce que l'objet est exactement le verrouillage, et pour quel but.

Notez également qu'il existe des situations dans lesquelles vous souhaitez côté client synchroniser des blocs de code dans lequel le moniteur que vous demandez (c'est à dire l'objet synchronisé) n'est pas nécessairement this, comme dans cet exemple :

Vector v = getSomeGlobalVector();
synchronized (v) {
    // some thread-safe operation on the vector
}

Je vous suggère d'obtenir plus de connaissances sur la programmation simultanée, il vous servira beaucoup une fois que vous savez exactement ce qui se passe derrière les coulisses. Vous devriez vérifier la Programmation Simultanée en Java, un grand livre sur le sujet. Si vous voulez une petite plongée dans le sujet, découvrez Java Simultanéité @ Soleil

44voto

Bombe Points 34185

J'essaie d'éviter la synchronisation sur this car cela permettrait à toutes les personnes de l'extérieur qui avaient une référence à cet objet de bloquer ma synchronisation. Au lieu de cela, je crée un objet de synchronisation local:

 public class Foo {
    private final Object syncObject = new Object();
    …
}
 

Maintenant, je peux utiliser cet objet pour la synchronisation sans craindre que quiconque "vole" le verrou.

6voto

Kent Lai Points 841

Juste pour souligner qu'il y a aussi ReadWriteLocks disponible en Java, a trouvé que java.util.de façon concomitante.les verrous.ReadWriteLock.

Dans la plupart de mon utilisation, j'ai séparé ma verrouillage "pour la lecture" et "pour les mises à jour". Si vous utilisez simplement un mot-clé synchronized, toutes les lectures de la même méthode/bloc de code sera "en attente'. Un seul thread peut accéder au bloc à la fois.

Dans la plupart des cas, vous n'aurez jamais à vous soucier des problèmes de concurrence, si vous êtes tout simplement faire la lecture. C'est quand que vous faites de l'écriture que vous vous inquiétez au sujet de mises à jour simultanées (entraînant des pertes de données), ou de la lecture lors d'une écriture (des mises à jour partielles), que vous avez à vous soucier.

Donc un verrou lecture/écriture plus de sens pour moi au cours de multi-thread de programmation.

4voto

Electric Monk Points 1020

Vous aurez envie de les synchroniser sur un objet qui peut servir comme un Mutex. Si l'instance courante ( cette référence) est adapté (pas un Singleton, par exemple), vous pouvez l'utiliser, comme en Java, tout Objet peut servir comme le Mutex.

En d'autres occasions, vous voudrez peut-être partager un Mutex entre plusieurs classes, si les instances de ces classes peuvent tous avoir accès aux mêmes ressources.

Cela dépend beaucoup de l'environnement dans lequel vous travaillez et le type de système que vous êtes en train de construire. Dans la plupart des applications Java EE que j'ai vu, il n'existe pas de réel besoin pour la synchronisation...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X