Oggi daremo un’occhiata a AtomicInteger
in Java. Le operazioni atomiche vengono eseguite in un’unica unità di compito senza interferenze da altre operazioni. Le operazioni atomiche sono necessarie in un ambiente multithreading per evitare l’incoerenza dei dati.
AtomicInteger
Creiamo un semplice programma multithreading in cui ogni thread incrementa la variabile
count
condivisa 4 volte. Quindi, se ci sono due thread, dopo che hanno terminato, il valore di count
dovrebbe essere 8. JavaAtomic.java
package com.journaldev.concurrency;
public class JavaAtomic {
public static void main(String[] args) throws InterruptedException {
ProcessingThread pt = new ProcessingThread();
Thread t1 = new Thread(pt, "t1");
t1.start();
Thread t2 = new Thread(pt, "t2");
t2.start();
t1.join();
t2.join();
System.out.println("Processing count=" + pt.getCount());
}
}
class ProcessingThread implements Runnable {
private int count;
@Override
public void run() {
for (int i = 1; i < 5; i++) {
processSomething(i);
count++;
}
}
public int getCount() {
return this.count;
}
private void processSomething(int i) {
// elaborazione di un lavoro
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Se esegui il programma sopra, noterai che il valore di count
varia tra 5, 6, 7, 8. Il motivo è perché count++ non è un’operazione atomica. Quindi, nel momento in cui un thread legge il suo valore e lo incrementa di uno, l’altro thread ha letto il valore precedente, portando a un risultato errato. Per risolvere questo problema, dovremo assicurarci che l’operazione di incremento su count sia atomica, possiamo farlo usando Synchronization ma Java 5 java.util.concurrent.atomic
fornisce classi wrapper per int e long che possono essere utilizzate per ottenere questa operazione atomica senza utilizzo di Synchronization.
Esempio di AtomicInteger Java
Ecco il programma aggiornato che restituirà sempre il valore del contatore come 8 perché il metodo incrementAndGet()
di AtomicInteger
incrementa atomicamente il valore corrente di uno.
package com.journaldev.concurrency;
import java.util.concurrent.atomic.AtomicInteger;
public class JavaAtomic {
public static void main(String[] args) throws InterruptedException {
ProcessingThread pt = new ProcessingThread();
Thread t1 = new Thread(pt, "t1");
t1.start();
Thread t2 = new Thread(pt, "t2");
t2.start();
t1.join();
t2.join();
System.out.println("Processing count=" + pt.getCount());
}
}
class ProcessingThread implements Runnable {
private AtomicInteger count = new AtomicInteger();
@Override
public void run() {
for (int i = 1; i < 5; i++) {
processSomething(i);
count.incrementAndGet();
}
}
public int getCount() {
return this.count.get();
}
private void processSomething(int i) {
// elaborazione di un lavoro
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I vantaggi dell’utilizzo delle classi di concorrenza per le operazioni atomiche sono che non è necessario preoccuparsi della sincronizzazione. Ciò migliora la leggibilità del codice e riduce la probabilità di errori. Inoltre, le operazioni atomiche delle classi di concorrenza sono considerate più efficienti della sincronizzazione, che coinvolge il blocco delle risorse.
Source:
https://www.digitalocean.com/community/tutorials/atomicinteger-java