Quelqu'un peut-il me dire l'avantage de la méthode synchronisée sur le bloc synchronisé avec un exemple?
401
Quelqu'un peut-il me dire l'avantage de la méthode synchronisée sur le bloc synchronisé avec un exemple?
Réponses:
Il n'y a pas d'avantage clair à utiliser la méthode synchronisée sur le bloc.
Peut-être que le seul (mais je n'appellerais pas cela un avantage) est que vous n'avez pas besoin d'inclure la référence de l'objet
this
.Méthode:
Bloquer:
Voir? Aucun avantage du tout.
Les blocs n'ont des avantages par rapport aux méthodes bien, la plupart du temps en flexibilité parce que vous pouvez utiliser un autre objet comme verrou alors que la synchronisation de la méthode bloquerait l'objet entier.
Comparer:
contre.
De plus, si la méthode se développe, vous pouvez toujours garder la section synchronisée séparée:
la source
synchronized
bloc est implémenté à l'aide de deux instructionsmonitorenter
etmonitorexit
, plus un gestionnaire d'exceptions qui garantit qu'ilmonitorexit
est appelé même dans le cas exceptionnel. Tout cela est enregistré lors de l'utilisation d'unesynchronized
méthode.La seule vraie différence est qu'un bloc synchronisé peut choisir sur quel objet il se synchronise. Une méthode synchronisée peut uniquement utiliser
'this'
(ou l'instance de classe correspondante pour une méthode de classe synchronisée). Par exemple, ceux-ci sont sémantiquement équivalents:Ce dernier est plus flexible car il peut rivaliser pour le verrou associé à n'importe quel objet, souvent une variable membre. Il est également plus granulaire car vous pourriez avoir du code simultané en cours d'exécution avant et après le bloc mais toujours dans la méthode. Bien sûr, vous pouvez tout aussi facilement utiliser une méthode synchronisée en refactorisant le code simultané dans des méthodes non synchronisées distinctes. Utilisez celui qui rend le code plus compréhensible.
la source
Méthode synchronisée
Avantages:
Les inconvénients:
Bloc synchronisé
Avantages:
Les inconvénients:
Personnellement, je préfère utiliser des méthodes synchronisées avec des classes axées uniquement sur la chose nécessitant une synchronisation. Cette classe doit être aussi petite que possible et il doit donc être facile de revoir la synchronisation. D'autres ne devraient pas avoir à se soucier de la synchronisation.
la source
La principale différence est que si vous utilisez un bloc synchronisé, vous pouvez verrouiller un objet autre que celui- ci, ce qui permet d'être beaucoup plus flexible.
Supposons que vous ayez une file d'attente de messages et plusieurs producteurs et consommateurs de messages. Nous ne voulons pas que les producteurs interfèrent les uns avec les autres, mais les consommateurs devraient pouvoir récupérer les messages sans avoir à attendre les producteurs. Donc on crée juste un objet
Et à partir de maintenant, chaque fois qu'un producteur veut ajouter un nouveau message, nous nous en tenons à cela:
Les consommateurs peuvent donc toujours lire et les producteurs seront verrouillés.
la source
Méthode synchronisée
Les méthodes synchronisées ont deux effets.
Tout d'abord, lorsqu'un thread exécute une méthode synchronisée pour un objet, tous les autres threads qui appellent des méthodes synchronisées pour le même bloc d'objet (suspendre l'exécution) jusqu'à ce que le premier thread soit terminé 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 de l'état de l'objet sont visibles pour tous les threads.
Notez que les constructeurs ne peuvent pas être synchronisés - l'utilisation du mot clé synchronized avec un constructeur est une erreur de syntaxe. La synchronisation des constructeurs n'a pas de sens, car seul le thread qui crée un objet doit y avoir accès pendant sa construction.
Instruction synchronisée
Contrairement aux méthodes synchronisées, les instructions synchronisées doivent spécifier l'objet qui fournit le verrou intrinsèque: le plus souvent, je l'utilise pour synchroniser l'accès à une liste ou une carte, mais je ne veux pas bloquer l'accès à toutes les méthodes de l'objet.
Q: Verrous intrinsèques et synchronisation La synchronisation est construite autour d'une entité interne connue sous le nom de verrou intrinsèque ou verrou de moniteur. (La spécification API fait souvent référence à cette entité simplement comme un "moniteur".) Les verrous intrinsèques jouent un rôle dans les deux aspects de la synchronisation: en imposant un accès exclusif à l'état d'un objet et en établissant des relations avant-événement qui sont essentielles à la visibilité.
Chaque objet a un verrou intrinsèque qui lui est associé. Par convention, un thread qui a besoin d'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 fini avec eux. Un thread est censé posséder le verrou intrinsèque entre le moment où il a acquis le verrou et l'a libéré. Tant qu'un thread possède un verrou intrinsèque, aucun autre thread ne peut acquérir le même verrou. L'autre thread se bloquera lorsqu'il tentera d'acquérir le verrou.
Vérification croisée des différentes sorties avec méthode synchronisée, bloc et sans synchronisation.
la source
Remarque: les méthodes et les blocs synchronisés statiques fonctionnent sur l'objet Class.
la source
Lorsque le compilateur java convertit votre code source en code octet, il gère les méthodes synchronisées et les blocs synchronisés très différemment.
Lorsque la JVM exécute une méthode synchronisée, le thread d'exécution identifie que la structure method_info de la méthode a le drapeau ACC_SYNCHRONIZED défini, puis elle acquiert automatiquement le verrou de l'objet, appelle la méthode et libère le verrou. Si une exception se produit, le thread libère automatiquement le verrou.
La synchronisation d'un bloc de méthode, d'autre part, contourne la prise en charge intégrée de la JVM pour l'acquisition du verrouillage d'objet et de la gestion des exceptions et nécessite que la fonctionnalité soit explicitement écrite en code octet. Si vous lisez le code d'octet d'une méthode avec un bloc synchronisé, vous verrez plus d'une douzaine d'opérations supplémentaires pour gérer cette fonctionnalité.
Cela montre les appels pour générer à la fois une méthode synchronisée et un bloc synchronisé:
La
synchronizedMethodGet()
méthode génère le code d'octet suivant:Et voici le code d'octet de la
synchronizedBlockGet()
méthode:Une différence significative entre la méthode synchronisée et le bloc est que, le bloc synchronisé réduit généralement la portée du verrouillage. Comme la portée du verrouillage est inversement proportionnelle aux performances, il est toujours préférable de verrouiller uniquement la section critique du code. L'un des meilleurs exemples d'utilisation de bloc synchronisé est le verrouillage à double vérification dans le modèle Singleton où, au lieu de verrouiller la
getInstance()
méthode entière , nous verrouillons uniquement la section critique du code qui est utilisée pour créer une instance Singleton. Cela améliore considérablement les performances car le verrouillage n'est requis qu'une ou deux fois.Lorsque vous utilisez des méthodes synchronisées, vous devrez faire très attention si vous mélangez des méthodes synchronisées synchronisées statiques et non statiques.
la source
monitorenter
etmonitorexit
avant d'exécuter le code.Le plus souvent, je l'utilise pour synchroniser l'accès à une liste ou une carte, mais je ne veux pas bloquer l'accès à toutes les méthodes de l'objet.
Dans le code suivant, un thread modifiant la liste ne bloquera pas l'attente d'un thread qui modifie la carte. Si les méthodes étaient synchronisées sur l'objet, chaque méthode devrait attendre, même si les modifications qu'elles apportent n'entreraient pas en conflit.
la source
Avec les blocs synchronisés, vous pouvez avoir plusieurs synchroniseurs, de sorte que plusieurs choses simultanées mais non conflictuelles puissent continuer en même temps.
la source
Les méthodes synchronisées peuvent être vérifiées à l'aide de l'API de réflexion. Cela peut être utile pour tester certains contrats, tels que toutes les méthodes du modèle sont synchronisées .
L'extrait de code suivant imprime toutes les méthodes synchronisées de Hashtable:
la source
Remarque importante sur l'utilisation du bloc synchronisé: faites attention à ce que vous utilisez comme objet de verrouillage!
L'extrait de code de user2277816 ci-dessus illustre ce point en ce qu'une référence à un littéral de chaîne est utilisée comme objet de verrouillage. Sachez que les littéraux de chaîne sont automatiquement internés en Java et vous devriez commencer à voir le problème: chaque morceau de code qui se synchronise sur le "verrou" littéral, partage le même verrou! Cela peut facilement conduire à des blocages avec des morceaux de code complètement indépendants.
Ce ne sont pas seulement les objets String avec lesquels vous devez faire attention. Les primitives encadrées sont également un danger, car les méthodes de zone automatique et les méthodes valueOf peuvent réutiliser les mêmes objets, selon la valeur.
Pour plus d'informations, voir: https://www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused
la source
Souvent, l'utilisation d'un verrou au niveau d'une méthode est trop grossière. Pourquoi verrouiller un morceau de code qui n'accède à aucune ressource partagée en verrouillant une méthode entière. Étant donné que chaque objet a un verrou, vous pouvez créer des objets factices pour implémenter la synchronisation au niveau du bloc. Le niveau de bloc est plus efficace car il ne verrouille pas toute la méthode.
Voici un exemple
Niveau de méthode
Niveau de bloc
[Éditer]
Pour les
Collection
mêmesVector
etHashtable
ils sont synchronisés quandArrayList
ouHashMap
ne le sont pas et vous devez définir un mot clé synchronisé ou invoquer la méthode synchronisée des collections:la source
La seule différence: les blocs synchronisés permettent un verrouillage granulaire contrairement à la méthode synchronisée
Fondamentalement
synchronized
, des méthodes ou des blocs ont été utilisés pour écrire du code thread-safe en évitant les erreurs d'incohérence de mémoire.Cette question est très ancienne et beaucoup de choses ont changé au cours des 7 dernières années. De nouvelles constructions de programmation ont été introduites pour la sécurité des threads.
Vous pouvez garantir la sécurité des threads en utilisant une API de concurrence avancée au lieu de
synchronied
blocs. Cette page de documentation fournit de bonnes constructions de programmation pour assurer la sécurité des threads.Les objets de verrouillage prennent en charge les idiomes de verrouillage qui simplifient de nombreuses applications simultanées.
Les exécuteurs définissent une API de haut niveau pour lancer et gérer les threads. Les implémentations d'exécuteur fournies par java.util.concurrent fournissent une gestion de pool de threads adaptée aux applications à grande échelle.
Les collections simultanées facilitent la gestion de grandes collections de données et peuvent considérablement réduire le besoin de synchronisation.
Les variables atomiques ont des fonctionnalités qui minimisent la synchronisation et aident à éviter les erreurs de cohérence de la mémoire.
ThreadLocalRandom (dans JDK 7) fournit une génération efficace de nombres pseudo-aléatoires à partir de plusieurs threads.
Un meilleur remplacement pour synchronisé est ReentrantLock , qui utilise l'
Lock
APIExemple avec serrures:
Reportez-vous à java.util.concurrent et java.util.concurrent.atomic packages pour d'autres constructions de programmation.
Reportez-vous également à cette question connexe:
Synchronisation vs verrouillage
la source
La méthode synchronisée est utilisée pour verrouiller tous les objets Le bloc synchronisé est utilisé pour verrouiller un objet spécifique
la source
En général, ce sont essentiellement les mêmes, sauf qu'elles sont explicites sur le moniteur de l'objet utilisé par rapport à l'implicite de cet objet. Un inconvénient des méthodes synchronisées qui, je pense, est parfois négligé est qu'en utilisant la référence "this" pour se synchroniser, vous laissez ouverte la possibilité de verrouillage d'objets externes sur le même objet. Cela peut être un bug très subtil si vous le rencontrez. La synchronisation sur un objet explicite interne ou tout autre champ existant peut éviter ce problème, encapsulant complètement la synchronisation.
la source
Comme déjà dit ici, le bloc synchronisé peut utiliser une variable définie par l'utilisateur comme objet de verrouillage, lorsque la fonction synchronisée utilise uniquement "ceci". Et bien sûr, vous pouvez manipuler des zones de votre fonction qui doivent être synchronisées. Mais tout le monde dit qu'il n'y a pas de différence entre la fonction synchronisée et le bloc qui couvre toute la fonction en utilisant "ceci" comme objet de verrouillage. Ce n'est pas vrai, la différence est dans le code d'octet qui sera généré dans les deux situations. En cas d'utilisation de bloc synchronisée, une variable locale doit être allouée qui contient une référence à "ceci". Et en conséquence, nous aurons une taille un peu plus grande pour la fonction (non pertinent si vous n'avez que peu de fonctions).
Une explication plus détaillée de la différence que vous pouvez trouver ici: http://www.artima.com/insidejvm/ed2/threadsynchP.html
la source
En cas de méthodes synchronisées, le verrouillage sera acquis sur un objet. Mais si vous optez pour un bloc synchronisé, vous avez la possibilité de spécifier un objet sur lequel le verrou sera acquis.
Exemple :
la source
Je sais que c'est une vieille question, mais avec ma lecture rapide des réponses ici, je n'ai vraiment vu personne mentionner que parfois une
synchronized
méthode peut être le mauvais verrou.Extrait de Java Concurrency In Practice (p. 72):
Le code ci - dessus a l' apparence d'être thread-safe. Cependant, en réalité, ce n'est pas le cas. Dans ce cas, le verrou est obtenu sur l'instance de la classe. Cependant, il est possible que la liste soit modifiée par un autre thread n'utilisant pas cette méthode. L'approche correcte serait d'utiliser
Le code ci-dessus empêcherait tous les threads essayant de modifier la liste de modifier la liste jusqu'à ce que le bloc synchronisé soit terminé.
la source
List
peut entraîner des problèmes de performances s'il existe un journal de code qui n'a pas nécessairement besoin d'être synchroniséEn pratique, l'avantage des méthodes synchronisées par rapport aux blocs synchronisés est qu'elles sont plus résistantes aux idiots; parce que vous ne pouvez pas choisir un objet arbitraire à verrouiller, vous ne pouvez pas abuser de la syntaxe de la méthode synchronisée pour faire des choses stupides comme verrouiller un littéral de chaîne ou verrouiller le contenu d'un champ modifiable qui est modifié sous les threads.
D'un autre côté, avec les méthodes synchronisées, vous ne pouvez pas protéger le verrou d'être acquis par un thread qui peut obtenir une référence à l'objet.
Ainsi, l'utilisation de synchronized comme modificateur sur les méthodes est meilleure pour protéger vos cow-orkers de se blesser, tandis que l'utilisation de blocs synchronisés en conjonction avec des objets de verrouillage final privés est meilleure pour protéger votre propre code contre les cow-orkers.
la source
À partir d'un résumé des spécifications Java: http://www.cs.cornell.edu/andru/javaspec/17.doc.html
Sur la base de ces descriptions, je dirais que la plupart des réponses précédentes sont correctes, et une méthode synchronisée pourrait être particulièrement utile pour les méthodes statiques, où vous auriez sinon à trouver comment obtenir "l'objet Class qui représente la classe dans laquelle la méthode était défini. "
Edit: Je pensais à l'origine qu'il s'agissait de citations de la spécification Java réelle. Clarifié que cette page n'est qu'un résumé / explication de la spécification
la source
TLDR;
synchronized
N'utilisez ni le modificateur ni l'synchronized(this){...}
expression, maissynchronized(myLock){...}
où semyLock
trouve un champ d'instance final contenant un objet privé.La différence entre l'utilisation du
synchronized
modificateur sur la déclaration de méthode et l'synchronized(..){ }
expression dans le corps de la méthode est la suivante:synchronized
modificateur spécifié sur la signature de la méthodesynchronized(this) { .... }
, etthis
objet comme verrou lorsqu'il est déclaré sur une méthode non statique ou la classe englobante lorsqu'il est déclaré sur une méthode statique.synchronized(...){...}
expression vous permetCependant, l'utilisation du
synchronized
modificateur ousynchronized(...) {...}
avecthis
comme objet de verrouillage (comme danssynchronized(this) {...}
) présente le même inconvénient. Les deux utilisent sa propre instance comme objet de verrouillage pour se synchroniser. Ceci est dangereux car non seulement l'objet lui-même mais tout autre objet / code externe qui contient une référence à cet objet peut également l'utiliser comme verrou de synchronisation avec des effets secondaires potentiellement graves (dégradation des performances et blocages ).Par conséquent, la meilleure pratique consiste à ne pas utiliser le
synchronized
modificateur ni l'synchronized(...)
expression conjointement avecthis
comme objet de verrouillage, mais un objet de verrouillage privé de cet objet. Par exemple:Vous pouvez également utiliser plusieurs objets de verrouillage, mais une attention particulière doit être prise pour garantir que cela n'entraîne pas de blocages lorsqu'ils sont imbriqués.
la source
Je suppose que cette question concerne la différence entre l' initialisation Thread Safe Singleton et lazy avec verrouillage Double check . Je me réfère toujours à cet article lorsque j'ai besoin d'implémenter un singleton spécifique.
Eh bien, ceci est un Singleton Thread Safe :
Il s'agit d'une initialisation paresseuse avec verrouillage à double vérification :
Veuillez vous référer à cet article pour plus de détails:
https://www.geeksforgeeks.org/java-singleton-design-pattern-practices-examples/
la source
Synchronisation avec les threads. 1) N'utilisez JAMAIS synchronisé (ceci) dans un thread cela ne fonctionne pas. La synchronisation avec (this) utilise le thread actuel comme objet de thread de verrouillage. Puisque chaque thread est indépendant des autres threads, il n'y a PAS de coordination de synchronisation. 2) Les tests de code montrent qu'en Java 1.6 sur Mac, la synchronisation de méthode ne fonctionne pas. 3) synchronisé (lockObj) où lockObj est un objet partagé commun de tous les threads qui se synchronisent dessus fonctionnera. 4) ReenterantLock.lock () et .unlock () fonctionnent. Voir les tutoriels Java pour cela.
Le code suivant montre ces points. Il contient également le vecteur thread-safe qui serait substitué à ArrayList, pour montrer que de nombreux threads s'ajoutant à un vecteur ne perdent aucune information, tandis que le même avec un ArrayList peut perdre des informations. 0) Le code actuel montre une perte d'informations en raison des conditions de concurrence A) Commentez la ligne A actuellement étiquetée et décommentez la ligne A au-dessus, puis exécutez, la méthode perd des données, mais elle ne devrait pas. B) Inversez l'étape A, décommentez B et // bloc de fin}. Ensuite, exécutez pour voir les résultats sans perte de données C) Commentez B, décommentez C. Exécutez, voir la synchronisation sur (ceci) perd les données, comme prévu. N'ayez pas le temps de terminer toutes les variantes, j'espère que cela vous aidera. Si la synchronisation sur (ceci) ou la synchronisation de méthode fonctionne, veuillez indiquer la version de Java et du système d'exploitation que vous avez testée. Je vous remercie.
la source