Pourquoi Queue.poll est-il plus rapide qu’itération? (java.util.concurrent.ConcurrentLinkedQueue)

J’ai un morceau de code qui extrait tous les éléments d’une queue. Je ne me soucie pas de l’état de la queue après coup et je peux être assuré que la queue ne sera pas modifiée pendant que j’en retire les éléments.

J’utilisais initialement un iterator pour extraire les éléments, car je pensais que ce serait plus rapide que d’interroger les éléments …

mais j’ai couru le test suivant:

ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue(); for (int i=0; i < 1000000; i++) queue.add(new Object()); LinkedList list = new LinkedList(); long start = System.currentTimeMillis(); for (Object object: queue) list.add(object); long time1 = System.currentTimeMillis() - start; list = new LinkedList(); start = System.currentTimeMillis(); Object object; while ((object = queue.poll()) != null) list.add(object); long time2 = System.currentTimeMillis() - start; System.out.println(time1 + " " + time2); 

J’ai eu la sortie suivante (moyenne sur 100 essais)

 1169 46 

Ma question est la suivante: pourquoi un sondage est-il plus rapide qu’itéré? Cela ne m’intéresse pas du tout, car poll devra modifier la file d’attente et itérer n’aura qu’à examiner l’état.

modifier — Gray avait raison

Je l’ai couru dans une boucle et ai obtenu la sortie (aurait dû le faire en premier lieu)

 1180 46 1422 25 287 32 14 26 226 26 236 25 12 26 14 25 13 25 13 26 13 25 268 25 13 25 14 176 13 26 13 26 13 25 13 25 13 26 13 24 13 26 13 25 ... 

Ma question est la suivante: pourquoi un sondage est-il plus rapide qu’itéré? Cela ne m’intéresse pas du tout, car poll devra modifier la file d’attente et itérer n’aura qu’à examiner l’état.

Comme @csoroiu le fait remarquer, cela semble être un problème de compilateur de points chauds. Étant donné le fonctionnement de Java, il est très important que vous “réchauffiez” votre application avant de commencer à effectuer des appels de synchronisation comme celui-ci.

Si je répète vos tests 100 fois avec une méthode, je voyais au départ des performances très différentes dues aux frais généraux du GC et à la magie de la JVM. Cependant, après l’ajout de méthodes .clear() et de System.gc() à la fin de la méthode, les chiffres de performance étaient plus cohérents avec la victoire de l’iterator:

 108 143 89 152 83 148 78 140 79 153 90 155 ... 

Voir la réponse de Peter ici pour plus de détails: temps d’exécution du processeur en Java

Pour une tonne d’informations supplémentaires sur la manière de procéder correctement au micro-benchmarking, voyez cette réponse exhaustive: Comment puis-je écrire un micro-benchmark correct en Java?