Que signifie “synchronisé”?

J’ai quelques questions concernant l’utilisation et la signification du mot clé synchronized .

  • Quelle est la signification du mot clé synchronized ?
  • Quand faut-il synchronized méthodes?
  • Qu’est-ce que cela signifie par programme et logiquement?

Le mot clé synchronized concerne tous les threads qui lisent et écrivent les mêmes variables, objects et ressources. Ce n’est pas un sujet sortingvial en Java, mais voici une citation de Sun:

synchronized méthodes synchronized permettent une stratégie simple de prévention des interférences de threads et des erreurs de cohérence de la mémoire: si un object est visible par plusieurs threads, toutes les lectures ou écritures sur ces variables sont effectuées via des méthodes synchronisées.

En quelques mots: lorsque vous avez deux threads qui lisent et écrivent sur la même «ressource», par exemple une variable nommée foo , vous devez vous assurer que ces threads accèdent à la variable de manière atomique. Sans le mot-clé synchronized , votre thread 1 ne verra peut-être pas le thread de modification 2 sur foo , ou pire, il ne pourra être modifié qu’à moitié. Ce ne serait pas ce que vous attendez logiquement.

Encore une fois, ceci est un sujet non sortingvial en Java. Pour en savoir plus, explorez les sujets sur SO et les interwebs sur:

  • Concurrence
  • Modèle de mémoire Java

Continuez à explorer ces sujets jusqu’à ce que le nom “Brian Goetz” devienne définitivement associé au terme “concurrence” dans votre cerveau.

Eh bien, je pense que nous en avons assez des explications théoriques, alors considérez ce code

 public class SOP { public static void print(Ssortingng s) { System.out.println(s+"\n"); } } public class TestThread extends Thread { Ssortingng name; TheDemo theDemo; public TestThread(Ssortingng name,TheDemo theDemo) { this.theDemo = theDemo; this.name = name; start(); } @Override public void run() { theDemo.test(name); } } public class TheDemo { public synchronized void test(Ssortingng name) { for(int i=0;i<10;i++) { SOP.print(name + " :: "+i); try{ Thread.sleep(500); } catch (Exception e) { SOP.print(e.getMessage()); } } } public static void main(String[] args) { TheDemo theDemo = new TheDemo(); new TestThread("THREAD 1",theDemo); new TestThread("THREAD 2",theDemo); new TestThread("THREAD 3",theDemo); } } 

Note: synchronized bloque l'appel du thread suivant à la méthode test () tant que l'exécution du thread précédent n'est pas terminée. Les threads peuvent accéder à cette méthode un par un. Sans synchronized tous les threads peuvent accéder à cette méthode simultanément.

Lorsqu'un thread appelle la méthode synchronisée "test" de l'object (ici l'object est une instance de la classe "TheDemo"), il acquiert le verrou de cet object, tout nouveau thread ne peut appeler ANY méthode synchronisée du même object aussi longtemps que le thread précédent qui avait acquis la serrure ne libère pas la serrure.

Une chose similaire se produit quand une méthode statique de la classe est appelée. Le thread acquiert le verrou associé à la classe (dans ce cas, toute méthode non statique synchronisée d'une instance de cette classe peut être appelée par n'importe quel thread, car ce locking de niveau d'object est toujours disponible). Tout autre thread ne pourra pas appeler une méthode synchronisée statique de la classe tant que le verrou de niveau de classe n'est pas libéré par le thread qui détient actuellement le verrou.

Sortie avec synchronisé

 THREAD 1 :: 0 THREAD 1 :: 1 THREAD 1 :: 2 THREAD 1 :: 3 THREAD 1 :: 4 THREAD 1 :: 5 THREAD 1 :: 6 THREAD 1 :: 7 THREAD 1 :: 8 THREAD 1 :: 9 THREAD 3 :: 0 THREAD 3 :: 1 THREAD 3 :: 2 THREAD 3 :: 3 THREAD 3 :: 4 THREAD 3 :: 5 THREAD 3 :: 6 THREAD 3 :: 7 THREAD 3 :: 8 THREAD 3 :: 9 THREAD 2 :: 0 THREAD 2 :: 1 THREAD 2 :: 2 THREAD 2 :: 3 THREAD 2 :: 4 THREAD 2 :: 5 THREAD 2 :: 6 THREAD 2 :: 7 THREAD 2 :: 8 THREAD 2 :: 9 

Sortie sans synchronisé

 THREAD 1 :: 0 THREAD 2 :: 0 THREAD 3 :: 0 THREAD 1 :: 1 THREAD 2 :: 1 THREAD 3 :: 1 THREAD 1 :: 2 THREAD 2 :: 2 THREAD 3 :: 2 THREAD 1 :: 3 THREAD 2 :: 3 THREAD 3 :: 3 THREAD 1 :: 4 THREAD 2 :: 4 THREAD 3 :: 4 THREAD 1 :: 5 THREAD 2 :: 5 THREAD 3 :: 5 THREAD 1 :: 6 THREAD 2 :: 6 THREAD 3 :: 6 THREAD 1 :: 7 THREAD 2 :: 7 THREAD 3 :: 7 THREAD 1 :: 8 THREAD 2 :: 8 THREAD 3 :: 8 THREAD 1 :: 9 THREAD 2 :: 9 THREAD 3 :: 9 

Le mot clé synchronized empêche l’access simultané à un bloc de code ou à un object par plusieurs threads. Par défaut, une table de Hashtable est synchronized , de sorte qu’un seul thread peut accéder à la table à la fois.

Lors de l’utilisation de constructions non-synchronized telles que HashMap , vous devez créer des fonctionnalités de sécurité des threads dans votre code pour éviter les erreurs de cohérence de la mémoire.

synchronized signifie que dans un environnement multi-thread, un object ayant synchronized méthodes / blocs synchronized ne permet pas à deux threads d’accéder synchronized méthodes / bloc (s) synchronized (s) de code. Cela signifie qu’un thread ne peut pas lire pendant qu’un autre thread le met à jour.

Le second thread attendra plutôt que le premier thread termine son exécution. La surcharge est la vitesse, mais l’avantage est la cohérence garantie des données.

Si votre application est à thread unique, synchronized blocs synchronized ne présentent aucun avantage.

Le mot-clé synchronized amène un thread à obtenir un verrou lors de la saisie de la méthode, de sorte qu’un seul thread peut exécuter la méthode en même temps (pour l’instance d’object donnée, sauf s’il s’agit d’une méthode statique).

Ceci est souvent appelé rendre la classe thread-safe, mais je dirais que c’est un euphémisme. S’il est vrai que la synchronisation protège l’état interne du vecteur contre la corruption, cela n’aide généralement pas beaucoup l’utilisateur de Vector.

Considère ceci:

  if (vector.isEmpty()){ vector.add(data); } 

Bien que les méthodes impliquées soient synchronisées, car elles sont verrouillées et déverrouillées individuellement, deux threads temporisés peuvent malheureusement créer un vecteur avec deux éléments.

Donc, en fait, vous devez également synchroniser votre code d’application.

Étant donné que la synchronisation au niveau de la méthode est a) coûteuse lorsque vous n’en avez pas besoin et b) insuffisante lorsque vous avez besoin de synchronisation, il existe désormais des remplacements non synchronisés (ArrayList dans le cas de Vector).

Plus récemment, le paquet de concurrence a été publié, avec un certain nombre d’utilitaires intelligents qui prennent en charge les problèmes de multithreading.

Vue d’ensemble

Le mot-clé synchronisé en Java est lié à la sécurité des threads, c’est-à-dire lorsque plusieurs threads lisent ou écrivent la même variable.
Cela peut se produire directement (en accédant à la même variable) ou indirectement (en utilisant une classe qui utilise une autre classe qui accède à la même variable).

Le mot-clé synchronized est utilisé pour définir un bloc de code où plusieurs threads peuvent accéder à la même variable de manière sûre.

Plus profond

Sur le plan de la syntaxe, le mot-clé synchronized prend un Object comme paramètre (appelé object verrou ), suivi d’un { block of code } .

  • Lorsque l’exécution rencontre ce mot-clé, le thread en cours essaie de “verrouiller / acquérir / posséder” l’ object de locking et d’exécuter le bloc de code associé après l’acquisition du verrou.

  • Toute écriture sur des variables à l’intérieur du bloc de code synchronisé est garantie d’être visible pour tout autre thread exécutant de la même manière du code dans un bloc de code synchronisé utilisant le même object de locking .

  • Un seul thread à la fois peut contenir le verrou, pendant lequel tous les autres threads essayant d’acquérir le même object de locking attendent (interrompent leur exécution). Le verrou sera libéré lorsque l’exécution quitte le bloc de code synchronisé.

Méthodes synchronisées:

L’ajout d’ synchronized mot-clé synchronized à une définition de méthode est égal à la totalité du corps de la méthode encapsulé dans un bloc de code synchronisé avec l’ object de locking (par exemple, méthodes) et ClassInQuestion.getClass() (pour les méthodes de classe) .

– La méthode d’instance est une méthode qui n’a pas de mot-clé static .
– La méthode de classe est une méthode qui a static mot-clé static .

Technique

Sans synchronisation, il n’est pas garanti dans quel ordre les lectures et les écritures se produisent, laissant éventuellement la variable avec des erreurs.
(Par exemple, une variable peut se retrouver avec la moitié des bits écrits par un thread et la moitié des bits écrits par un autre thread, laissant la variable dans un état qu’aucun des threads n’a essayé d’écrire, mais un désordre combiné.)

Il ne suffit pas d’effectuer une opération d’écriture dans un thread avant (heure de l’horloge), un autre thread le lit, car le matériel pourrait avoir mis en cache la valeur de la variable, et le thread de lecture verrait la valeur mise en cache au lieu de il.

Conclusion

Ainsi, dans le cas de Java, vous devez suivre le modèle de mémoire Java pour vous assurer que les erreurs de thread ne se produisent pas.
En d’autres termes, utilisez la synchronisation, les opérations atomiques ou les classes qui les utilisent pour vous sous le capot.

Sources

http://docs.oracle.com/javase/specs/jls/se8/html/index.html
Spécification du langage Java®, 2015-02-13

Pensez-y comme une sorte de tourniquet que vous pourriez trouver sur un terrain de football. Il y a des vapeurs parallèles de personnes qui veulent entrer, mais au tourniquet, elles sont «synchronisées». Une seule personne à la fois peut passer. Tous ceux qui veulent passer au travers le feront, mais ils devront peut-être attendre de pouvoir passer.

Quel est le mot clé synchronisé?

Les threads communiquent principalement en partageant l’access aux champs et aux objects auxquels les champs de référence font référence. Cette forme de communication est extrêmement efficace, mais rend possibles deux types d’erreurs: les interférences de threads et les erreurs de cohérence de mémoire . L’outil nécessaire pour éviter ces erreurs est la synchronisation.

Les blocs ou méthodes synchronisés empêchent les interférences de thread et garantissent la cohérence des données. À tout moment, un seul thread peut accéder à un bloc ou à une méthode synchronisée ( section critique ) en acquérant un verrou. D’autres threads attendent la libération du verrou pour accéder à la section critique .

Quand les méthodes sont-elles synchronisées?

Les méthodes sont synchronisées lorsque vous ajoutez synchronized à la définition ou à la déclaration de la méthode. Vous pouvez également synchroniser un bloc de code particulier avec une méthode.

Qu’est-ce que cela signifie pro grammaticalement et logiquement?

Cela signifie qu’un seul thread peut accéder à la section critique en acquérant un verrou. À moins que ce thread ne libère ce verrou, tous les autres threads devront attendre pour acquérir un verrou. Ils n’ont pas access à la section critique sans acquérir le locking.

Cela ne peut pas être fait avec une magie. C’est la responsabilité du programmeur d’identifier les sections critiques dans l’application et de les protéger en conséquence. Java fournit un cadre pour protéger votre application, mais où et quoi toutes les sections à protéger sont la responsabilité du programmeur.

Plus de détails sur la page de documentation de java

Serrures Insortingnsèques et Synchronisation:

La synchronisation est construite autour d’une entité interne appelée verrou insortingnsèque ou verrou de moniteur. Les verrous insortingnsèques jouent un rôle dans les deux aspects de la synchronisation: ils imposent un access exclusif à l’état d’un object et établissent des relations préalables essentielles à la visibilité.

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

On dit qu’un thread possède le verrou insortingnsèque entre le moment où il a acquis le verrou et le délocking du verrou. Tant qu’un thread possède un verrou insortingnsè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.

Lorsqu’un thread libère un verrou insortingnsèque, une relation se produit avant que cette action et toute acquisition ultérieure du même verrou ne soit établie.

La synchronisation des méthodes a deux effets :

D’abord, il n’est pas possible que deux invocations de méthodes synchronisées sur le même object soient entrelacées.

Lorsqu’un thread exécute une méthode synchronisée pour un object, tous les autres threads qui appellent des méthodes synchronisées pour le même bloc d’object (suspendre l’exécution) jusqu’à ce que le premier thread soit terminé avec l’object.

Deuxièmement, lorsqu’une méthode synchronisée se termine, elle établit automatiquement une relation “avant-précédent” avec toute invocation ultérieure d’une méthode synchronisée pour le même object.

Cela garantit que les modifications apscopes à l’état de l’object sont visibles pour tous les threads.

Recherchez d’autres alternatives à la synchronisation dans:

Évitez de synchroniser (ceci) en Java?

À ma connaissance, la synchronisation signifie essentiellement que le compilateur écrit un fichier monitor.enter et monitor.exit autour de votre méthode. En tant que tel, il peut être thread-safe selon son utilisation (ce que je veux dire, c’est que vous pouvez écrire un object avec des méthodes synchronisées qui ne sont pas threadsafe en fonction de ce que fait votre classe).

Je sais que vous avez déjà reçu votre réponse.
J’écris ceci, uniquement pour aider les personnes qui ont la même question et qui recherchent une réponse sur cette page.
voici une explication de la documentation java :

Considérez le code suivant:

 public class SynchronizedCounter { private int c = 0; public synchronized void increment() { c++; } public synchronized void decrement() { c--; } public synchronized int value() { return c; } } 

Si count est une instance de SynchronizedCounter alors la SynchronizedCounter ces méthodes a deux effets:

  • D’abord, il n’est pas possible que deux invocations de méthodes synchronisées sur le même object soient entrelacées. Lorsqu’un thread exécute une méthode synchronisée pour un object, tous les autres threads qui appellent des méthodes synchronisées pour le même bloc d’object (suspendre l’exécution) jusqu’à ce que le premier thread soit terminé avec l’object.
  • Deuxièmement, lorsqu’une méthode synchronisée se termine, elle établit automatiquement une relation “avant-précédent” avec toute invocation ultérieure d’une méthode synchronisée pour le même object. Cela garantit que les modifications apscopes à l’état de l’object sont visibles pour tous les threads.

Synchronized normal method équivalente à l’ Synchronized statement (utilisez ceci)

 class A { public synchronized void methodA() { // all function code } equivalent to public void methodA() { synchronized(this) { // all function code } } } 

Synchronized static method équivalente à l’ Synchronized statement (classe d’utilisation)

 class A { public static synchronized void methodA() { // all function code } equivalent to public void methodA() { synchronized(A.class) { // all function code } } } 

Instruction synchronisée (en utilisant la variable)

 class A { private Object lock1 = new Object(); public void methodA() { synchronized(lock1 ) { // all function code } } } 

Pour synchronized , nous avons à la fois des Synchronized Methods Synchronized Statements et des Synchronized Statements . Cependant, les Synchronized Methods sont similaires aux Synchronized Statements , il suffit donc de comprendre les Synchronized Statements .

=> Fondamentalement, nous aurons

 synchronized(object or class) { // object/class use to provides the insortingnsic lock // code } 

Voici 2 pense que aide la compréhension synchronized

  • Chaque object / classe est associé à un insortingnsic lock .
  • Lorsqu’un thread appelle une synchronized statement , il acquiert automatiquement le insortingnsic lock de synchronized statement's object synchronized statement's cette synchronized statement's et le libère lorsque la méthode retourne. Tant qu’un thread possède un insortingnsic lock , aucun autre thread ne peut acquérir le verrou SAME => thread safe.

=> Lorsqu’un thread A invoque synchronized(this){// code 1} => tout le code du bloc (dans la classe) où sont synchronized(this) et toutes synchronized normal method (dans la classe) sont verrouillées car SAME lock. Il s’exécutera après le thread A délocking (“// code 1” terminé).

Ce comportement est similaire à synchronized(a variable){// code 1} ou synchronized(class) .

SAME LOCK => lock (ne dépend pas de la méthode ou des instructions?)

Utilisez une méthode synchronisée ou des instructions synchronisées?

Je préfère synchronized statements car elles sont plus extensibles. Exemple, à l’avenir, vous aurez seulement besoin de synchroniser une partie de la méthode. Par exemple, vous avez 2 méthodes synchronisées et elles ne sont pas pertinentes l’ une par rapport à l’autre. Cependant, lorsqu’un thread exécute une méthode, il bloque l’autre méthode (il peut empêcher l’utilisation d’ synchronized(a variable) ).

Cependant, appliquer la méthode synchronisée est simple et le code simple. Pour certaines classes, il n’y a qu’une méthode synchronisée ou toutes les méthodes synchronisées dans la classe qui sont pertinentes l’une par rapport à l’autre => nous pouvons utiliser la synchronized method pour rendre le code plus court et facile à comprendre

Remarque

(ce n’est pas pertinent pour beaucoup de synchronized , c’est la différence entre object et classe ou non-statique et statique).

  • Lorsque vous utilisez une méthode synchronized ou normale ou une méthode synchronized(this) ou synchronized(non-static variable) elle synchronisera la base sur chaque instance d’object.
  • Lorsque vous utilisez une méthode synchronized ou statique ou synchronized(class) ou synchronized(static variable) , la base sera synchronisée sur la classe

Référence

https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

J’espère que ça aide

Ce qui manque aux autres réponses, c’est un aspect important: les obstacles à la mémoire . La synchronisation des threads se compose essentiellement de deux parties: la sérialisation et la visibilité. Je conseille à tous de google pour “jvm memory barrier”, car c’est un sujet non sortingvial et extrêmement important (si vous modifiez des données partagées accessibles par plusieurs threads). Ayant fait cela, je conseille de regarder les classes du paquet java.util.concurrent qui évitent d’utiliser une synchronisation explicite, ce qui aide à garder les programmes simples et efficaces, peut-être même à prévenir les blocages.

Un exemple est ConcurrentLinkedDeque . Avec le modèle de commande, cela permet de créer des threads de travail très efficaces en plaçant les commandes dans la queue simultanée – pas de synchronisation explicite nécessaire, pas de blocages possibles, pas de sumil explicite nécessaire, il suffit d’interroger la file en appelant take ().

En bref: “la synchronisation de la mémoire” se produit implicitement lorsque vous démarrez un thread, un thread se termine, vous lisez une variable volatile, vous déverrouillez un moniteur (laissez un bloc / une fonction synchronisé), etc. “) toutes les écritures faites avant cette action particulière. Dans le cas du ConcurrentLinkedDeque susmentionné, la documentation “indique”:

Effets de cohérence de la mémoire: comme pour les autres collections simultanées, les actions d’un thread avant de placer un object dans un ConcurrentLinkedDeque se produisent avant les actions après l’access ou la suppression de cet élément de ConcurrentLinkedDeque dans un autre thread.

Ce comportement implicite est un aspect un peu pernicieux, car la plupart des programmeurs Java n’ont pas beaucoup d’expérience. Et puis soudainement trébucher sur ce thread après que Java ne fasse pas ce qu’il est “censé” faire dans la production où il y a une charge de travail différente – et il est assez difficile de tester les problèmes de concurrence.

synchronized simple signifie qu’aucun deux threads ne peuvent accéder au bloc / à la méthode simultanément. Lorsque nous disons qu’un bloc / méthode d’une classe est synchronisé, cela signifie qu’un seul thread peut y accéder à la fois. En interne, le thread qui tente d’y accéder commence par verrouiller cet object et, tant que ce verrou n’est pas disponible, aucun autre thread ne peut accéder aux méthodes / blocs synchronisés de cette instance de la classe.

Notez qu’un autre thread peut accéder à une méthode du même object qui n’est pas définie pour être synchronisée. Un thread peut libérer le verrou en appelant

 Object.wait() 

Synchronisé signifie simplement que plusieurs threads, s’ils sont associés à un object unique, peuvent empêcher la lecture et l’écriture sales si le bloc synchronisé est utilisé sur un object particulier. Pour vous donner plus de clarté, prenons un exemple:

 class MyRunnable implements Runnable { int var = 10; @Override public void run() { call(); } public void call() { synchronized (this) { for (int i = 0; i < 4; i++) { var++; System.out.println("Current Thread " + Thread.currentThread().getName() + " var value "+var); } } } } public class MutlipleThreadsRunnable { public static void main(String[] args) { MyRunnable runnable1 = new MyRunnable(); MyRunnable runnable2 = new MyRunnable(); Thread t1 = new Thread(runnable1); t1.setName("Thread -1"); Thread t2 = new Thread(runnable2); t2.setName("Thread -2"); Thread t3 = new Thread(runnable1); t3.setName("Thread -3"); t1.start(); t2.start(); t3.start(); } } 

Nous avons créé deux objects de classe MyRunnable, runnable1 étant partagé avec le thread 1 et le thread 3 & runnable2 étant partagé avec le thread 2 uniquement. Maintenant, lorsque t1 et t3 commencent sans être synchronisés, la sortie PFB qui suggère que les deux threads 1 et 3 affectent simultanément la valeur var où pour le thread 2, var a sa propre mémoire.

 Without Synchronized keyword Current Thread Thread -1 var value 11 Current Thread Thread -2 var value 11 Current Thread Thread -2 var value 12 Current Thread Thread -2 var value 13 Current Thread Thread -2 var value 14 Current Thread Thread -1 var value 12 Current Thread Thread -3 var value 13 Current Thread Thread -3 var value 15 Current Thread Thread -1 var value 14 Current Thread Thread -1 var value 17 Current Thread Thread -3 var value 16 Current Thread Thread -3 var value 18 

En utilisant Synchronzied, le thread 3 attend que le thread 1 se termine dans tous les scénarios. Il y a deux verrous acquis, un sur runnable1 partagé par le thread 1 et le thread 3 et un autre sur runnable2 partagé par le thread 2 uniquement.

 Current Thread Thread -1 var value 11 Current Thread Thread -2 var value 11 Current Thread Thread -1 var value 12 Current Thread Thread -2 var value 12 Current Thread Thread -1 var value 13 Current Thread Thread -2 var value 13 Current Thread Thread -1 var value 14 Current Thread Thread -2 var value 14 Current Thread Thread -3 var value 15 Current Thread Thread -3 var value 16 Current Thread Thread -3 var value 17 Current Thread Thread -3 var value 18 

synchronized est un mot-clé en Java qui est utilisé pour que les relations se produisent dans un environnement multithreading afin d’éviter les incohérences de mémoire et les erreurs d’interférence de thread.