Pourquoi est-ce que i++
non atomique en Java ?
Pour aller un peu plus loin dans Java, j'ai essayé de compter combien de fois les boucles dans les threads sont exécutées.
J'ai donc utilisé un
private static int total = 0;
dans la classe principale.
J'ai deux fils.
- Fil conducteur 1 : Impressions
System.out.println("Hello from Thread 1!");
- Fil conducteur 2 : Impressions
System.out.println("Hello from Thread 2!");
Et je compte les lignes imprimées par le fil 1 et le fil 2. Mais les lignes du fil 1 + les lignes du fil 2 ne correspondent pas au nombre total de lignes imprimées.
Voici mon code :
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Test {
private static int total = 0;
private static int countT1 = 0;
private static int countT2 = 0;
private boolean run = true;
public Test() {
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
newCachedThreadPool.execute(t1);
newCachedThreadPool.execute(t2);
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
run = false;
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println((countT1 + countT2 + " == " + total));
}
private Runnable t1 = new Runnable() {
@Override
public void run() {
while (run) {
total++;
countT1++;
System.out.println("Hello #" + countT1 + " from Thread 2! Total hello: " + total);
}
}
};
private Runnable t2 = new Runnable() {
@Override
public void run() {
while (run) {
total++;
countT2++;
System.out.println("Hello #" + countT2 + " from Thread 2! Total hello: " + total);
}
}
};
public static void main(String[] args) {
new Test();
}
}
14 votes
Pourquoi n'essayez-vous pas avec
AtomicInteger
?7 votes
Voir aussi : une autre question sur le SO , ++ non considéré comme atomique , Concurrence en Java .
0 votes
@user2864740, pourquoi dites-vous que AtomicInteger n'est pas atomique ? Vous pouvez utiliser le [getAndIncrement](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicInteger.html#getAndIncrement()) pour ce faire. Elle est atomique.
3 votes
La JVM a un
iinc
pour incrémenter des entiers, mais cela ne fonctionne que pour les variables locales, où la concurrence n'est pas un problème. Pour les champs, le compilateur génère séparément les commandes de lecture-modification-écriture.14 votes
Pourquoi vous attendriez-vous à ce qu'il soit atomique ?
1 votes
Même sur un matériel qui implémente une instruction "incrémenter l'emplacement de stockage", il n'y a aucune garantie que cela soit sûr pour les fils. Ce n'est pas parce qu'une opération peut être représentée par un seul opérateur qu'elle est sûre pour les threads.
2 votes
@Silly Freak : même s'il y avait une
iinc
pour les champs, le fait de n'avoir qu'une seule instruction ne garantit pas l'atomicité, par exemple en cas d'absence d'instruction.volatile
long
ydouble
L'accès aux champs n'est pas garanti comme étant atomique, même s'il est effectué par une seule instruction du bytecode.0 votes
Cette question souligne l'utilité de l'apprentissage du langage assembleur.