logo

Java atomique

En Java, variables atomiques et opérations utilisé en simultanéité. Le multithread l'environnement conduit à un problème lorsque concurrence est unifié. L'entité partagée telle que les objets et les variables peut être modifiée lors de l'exécution du programme. Par conséquent, ils peuvent conduire à une incohérence du programme. Il est donc important de prendre soin de l’entité partagée lors des accès simultanés. Dans de tels cas, le variable atomique peut être une solution. Dans cette section, nous discuterons classes atomiques, variables atomiques, opérations atomiques , accompagné d'exemples.

file d'attente prioritaire c++

Avant d'avancer dans cette section, assurez-vous d'être conscient de fil , synchronisation , et verrouillage en Java.

Classes atomiques Java

Java fournit un java.util.concurrent.atomic package dans lequel les classes atomiques sont définies. Les classes atomiques fournissent un sans verrouillage et thread-safe environnement ou programmation sur une seule variable. Il prend également en charge les opérations atomiques. Toutes les classes atomiques ont les méthodes get() et set() qui fonctionnent sur la variable volatile. La méthode fonctionne de la même manière que la lecture et l'écriture sur des variables volatiles.

Le package fournit les classes atomiques suivantes :

Classe Description
AtomiqueBooléen Il est utilisé pour mettre à jour la valeur booléenne de manière atomique.
Entier atomique Il est utilisé pour mettre à jour la valeur entière de manière atomique.
Tableau d'entiers atomiques Un tableau int dans lequel les éléments peuvent être mis à jour de manière atomique.
AtomicIntegerFieldUpdater Un utilitaire basé sur la réflexion qui permet des mises à jour atomiques des champs int volatiles désignés des classes désignées.
AtomiqueLong Il est utilisé pour mettre à jour une valeur longue de manière atomique.
TableauLongAtomique Un long tableau dans lequel les éléments peuvent être mis à jour de manière atomique.
AtomicLongFieldUpdater Un utilitaire basé sur la réflexion qui permet des mises à jour atomiques sur des champs longs volatils désignés de classes désignées.
AtomicMarkableRéférence Un AtomicMarkableReference maintient une référence d'objet avec un bit de marque, qui peut être mis à jour de manière atomique.
Référence atomique Une référence d'objet qui peut être mise à jour de manière atomique.
Tableau de référence atomique Un tableau de références d'objets dans lequel les éléments peuvent être mis à jour de manière atomique.
AtomicReferenceFieldUpdater Un utilitaire basé sur la réflexion qui permet des mises à jour atomiques des champs de référence volatiles désignés des classes désignées.
AtomicStampedRéférence Un AtomicStampedReference conserve une référence d'objet ainsi qu'un « tampon » entier, qui peut être mis à jour de manière atomique.
DoubleAccumulateur Une ou plusieurs variables qui, ensemble, maintiennent une valeur double courante mise à jour à l'aide d'une fonction fournie.
DoubleAdder Une ou plusieurs variables qui, ensemble, maintiennent une double somme initialement nulle.
Accumulateur long Une ou plusieurs variables qui, ensemble, maintiennent une valeur longue courante mise à jour à l'aide d'une fonction fournie.
Additionneur long Une ou plusieurs variables qui, ensemble, maintiennent une somme longue initialement nulle.

Les objets de ces classes représentent la variable atomique de int, long, booléen , et objet référence respectivement. Les classes atomiques ont certaines méthodes communes :

Méthodes Description
ensemble() Il est utilisé pour définir la valeur.
obtenir() Il est utilisé pour obtenir la valeur actuelle.
paresseuxSet() Finalement, il prend la valeur donnée.
comparerEtEnsemble Définit atomiquement la valeur sur la valeur mise à jour donnée si la valeur actuelle == la valeur attendue.

Opérations atomiques

Les opérations qui s'exécutent toujours ensemble sont connues sous le nom de opérations atomiques ou action atomique . Toutes les opérations atomiques s’exécutent efficacement d’un seul coup ou ne se produisent pas du tout. Trois les concepts clés associés aux actions atomiques en Java sont les suivants :

1. L'atomicité traite des actions et des ensembles d'actions qui ont invisible Par exemple, considérons l'extrait de code suivant :

 class NoAtomicOps { long counter=0; void increment() { for(;;) { count++; } } void decrement() { for(;;) { count--; } } //other statement } 

Dans le code ci-dessus, le comportement de l'exécution simultanée d'incrément() et decrément() est indéfini et pas prévisible .

2. La visibilité détermine quand l'effet d'un fil peut être vu par un autre. Par exemple, considérons l'extrait de code suivant :

 class InfiniteLoop { boolean done= false; void work() { //thread T2 read while(!done) { //do work } } void stopWork() { //thread T1 write done=true; } //statements } 

Dans le code ci-dessus, il est possible que le thread T2 ne s'arrête jamais même après que le thread T1 soit défini sur true. De plus, il n’y a pas de synchronisation entre les threads.

3. L'ordre détermine quand les actions dans un thread se produisent dans le désordre par rapport à un autre thread.

 class Order { boolean a=false; boolean b=false; void demo1() //thread T1 { a=true; b=true; } boolean demo2() //thread T2 { boolean r1=b; //sees true boolean r2=a; //sees false boolean r3=a; //sees true //returns true return (r1 && !r2) && r3; } } 

L'ordre dans lequel les champs a et b apparaissent dans le thread T2 peut différer de l'ordre dans lequel ils ont été définis dans le thread T1.

govinda

Comprenons-le à travers un exemple.

 public class AtomicExample { int count; public void incrementCount() { count=1; } 

Dans l'extrait de code ci-dessus, nous avons déclaré une variable de type int compter et à l'intérieur de la méthode IncreaseCount() lui a attribué la valeur 1. Dans un tel cas, soit tout se produirait ensemble, soit ne se produirait pas du tout. Il représente donc un opération atomique et l'opération est connue sous le nom de atomicité .

Considérons un autre extrait de code.

 public class AtomicExample { int count; public void incrementCount() { count=count+1; } 

Il semble que ce soit aussi une opération atomique, mais ce n’est pas le cas. Il s'agit d'une opération linéaire composée de trois opérations, à savoir lire, modifier et écrire. Il peut donc s’exécuter partiellement. Mais si nous utilisons le code ci-dessus dans un environnement multithread, cela crée un problème.

Supposons que nous ayons appelé le code ci-dessus dans un environnement monothread, la valeur mise à jour de count sera 2. Si nous appelons la méthode ci-dessus par deux threads distincts, ils accèdent tous deux à la variable en même temps et mettent également à jour la valeur de compter simultanément. Pour éviter cette situation, nous utilisons le fonctionnement atomique.

'algorithme du banquier'

Java prend en charge plusieurs types d'actions atomiques, les suivantes :

  • Volatil variables
  • Opérations atomiques de bas niveau (dangereuses)
  • Cours atomiques

Voyons comment créer une opération atomique.

Variable atomique

La variable atomique nous permet d'effectuer une opération atomique sur une variable. Les variables atomiques minimisent la synchronisation et aident à éviter les erreurs de cohérence de la mémoire. Par conséquent, il assure la synchronisation.

Le package atomique fournit les cinq variables atomiques suivantes :

  • Entier atomique
  • AtomiqueLong
  • AtomiqueBooléen
  • Tableau d'entiers atomiques
  • TableauLongAtomique

Le besoin d’une variable atomique

Considérons le code suivant.

encapsulation Java

Compteur.java

 class Counter extends Thread { // Counter Variable int count = 0; //the method starts the execution of a thread public void run() { int max = 1; //increments the counter variable up to specified max time for (int i = 0; i <max; i++) { count++; } public class counter static void main(string args[]) throws interruptedexception creating an instance of the c="new" counter(); four threads thread t1="new" thread(c, 'first'); t2="new" 'second'); t3="new" 'third'); t4="new" 'fourth'); by calling start() method, we have started t1.start(); t2.start(); t3.start(); t4.start(); main will wait for all until execution do not complete t1.join(); t2.join(); t3.join(); t4.join(); prints final value count variable system.out.println(c.count); < pre> <p> <strong>Output:</strong> </p> <pre> 4 </pre> <p>The above program gives the expected output if it is executed in a single-threaded environment. A multi-threaded environment may lead to unexpected output. The reason behind it that when two or more threads try to update the value at the same time then it may not update properly.</p> <p>Java offers <strong>two</strong> solutions to overcome this problem:</p> <ul> <li>By using lock and synchronization</li> <li>By using atomic variable</li> </ul> <p>Let&apos;s create a Java program and use an atomic variable to overcome the problem.</p> <h3>By using Atomic Variable</h3> <p> <strong>AtomicExample.java</strong> </p> <pre> class Counter extends Thread { // Counter Variable int count = 0; //the method starts the execution of a thread public void run() { int max = 1; //increments the counter variable up to specified max time for (int i = 0; i <max; i++) { count++; } public class counter static void main(string args[]) throws interruptedexception creating an instance of the c="new" counter(); four threads thread t1="new" thread(c, 'first'); t2="new" 'second'); t3="new" 'third'); t4="new" 'fourth'); by calling start() method, we have started t1.start(); t2.start(); t3.start(); t4.start(); main will wait for all until execution do not complete t1.join(); t2.join(); t3.join(); t4.join(); prints final value count variable system.out.println(c.count); < pre> <p> <strong>Output:</strong> </p> <pre> 4 </pre> <h2>Synchronized Vs. Atomic Vs. Volatile</h2> <table class="table"> <tr> <th>Synchronized</th> <th>Atomic</th> <th>Volatile</th> </tr> <tr> <td>It applies to methods only.</td> <td>It applies to variables only.</td> <td>It also applies to variables only.</td> </tr> <tr> <td>It ensures visibility along with atomicity.</td> <td>It also ensures visibility along with atomicity.</td> <td>It ensures visibility, not atomicity.</td> </tr> <tr> <td>We can&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> <td>It stores in RAM, so accessing volatile variables is fast. But it does not provide thread-safety and synchronization.</td> </tr> <tr> <td>It can be implemented as a synchronized block or a synchronized method.</td> <td>We can&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> </tr> <tr> <td>It can lock the same class object or a different class object.</td> <td>We can&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> </tr> </table> <hr></max;></pre></max;>

Le programme ci-dessus donne le résultat attendu s'il est exécuté dans un environnement monothread. Un environnement multithread peut conduire à des résultats inattendus. La raison derrière cela est que lorsque deux threads ou plus tentent de mettre à jour la valeur en même temps, celle-ci risque de ne pas se mettre à jour correctement.

Offres Java deux solutions pour surmonter ce problème:

  • En utilisant le verrouillage et la synchronisation
  • En utilisant une variable atomique

Créons un programme Java et utilisons une variable atomique pour résoudre le problème.

En utilisant la variable atomique

AtomicExample.java

 class Counter extends Thread { // Counter Variable int count = 0; //the method starts the execution of a thread public void run() { int max = 1; //increments the counter variable up to specified max time for (int i = 0; i <max; i++) { count++; } public class counter static void main(string args[]) throws interruptedexception creating an instance of the c="new" counter(); four threads thread t1="new" thread(c, \'first\'); t2="new" \'second\'); t3="new" \'third\'); t4="new" \'fourth\'); by calling start() method, we have started t1.start(); t2.start(); t3.start(); t4.start(); main will wait for all until execution do not complete t1.join(); t2.join(); t3.join(); t4.join(); prints final value count variable system.out.println(c.count); < pre> <p> <strong>Output:</strong> </p> <pre> 4 </pre> <h2>Synchronized Vs. Atomic Vs. Volatile</h2> <table class="table"> <tr> <th>Synchronized</th> <th>Atomic</th> <th>Volatile</th> </tr> <tr> <td>It applies to methods only.</td> <td>It applies to variables only.</td> <td>It also applies to variables only.</td> </tr> <tr> <td>It ensures visibility along with atomicity.</td> <td>It also ensures visibility along with atomicity.</td> <td>It ensures visibility, not atomicity.</td> </tr> <tr> <td>We can&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> <td>It stores in RAM, so accessing volatile variables is fast. But it does not provide thread-safety and synchronization.</td> </tr> <tr> <td>It can be implemented as a synchronized block or a synchronized method.</td> <td>We can&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> </tr> <tr> <td>It can lock the same class object or a different class object.</td> <td>We can&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> </tr> </table> <hr></max;>

Synchronisé contre. Atomique contre. Volatil

Synchronisé Atomique Volatil
Cela s’applique uniquement aux méthodes. Cela s'applique uniquement aux variables. Cela s’applique également uniquement aux variables.
Il assure la visibilité ainsi que l’atomicité. Il assure également la visibilité ainsi que l’atomicité. Il garantit la visibilité et non l’atomicité.
Nous ne pouvons pas réaliser la même chose. Nous ne pouvons pas réaliser la même chose. Il est stocké dans la RAM, ce qui permet d'accéder rapidement aux variables volatiles. Mais il ne fournit pas de sécurité des threads ni de synchronisation.
Il peut être implémenté sous forme de bloc synchronisé ou de méthode synchronisée. Nous ne pouvons pas réaliser la même chose. Nous ne pouvons pas réaliser la même chose.
Il peut verrouiller le même objet de classe ou un objet de classe différent. Nous ne pouvons pas réaliser la même chose. Nous ne pouvons pas réaliser la même chose.