为什么Queue.poll比迭代更快?(java.util.concurrent.ConcurrentLinkedQueue中)

nik*_*pen 7 java queue concurrency

我有一段代码可以从队列中获取所有元素.之后我不关心队列的状态,我可以确保在从中删除元素时不会修改队列.

我最初使用迭代器来拉取元素因为我认为它比轮询元素更快...

但我跑了以下测试:

ConcurrentLinkedQueue<Object> queue = new ConcurrentLinkedQueue<>();
for (int i=0; i < 1000000; i++)
    queue.add(new Object());

LinkedList<Object> 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);
Run Code Online (Sandbox Code Playgroud)

我得到以下输出(平均超过100次运行)

1169 46
Run Code Online (Sandbox Code Playgroud)

我的问题是:为什么民意调查比迭代更快?这对我来说完全不直观,因为poll必须修改队列,迭代只需要查看状态.

编辑---格雷是对的

我在一个循环中运行它并获得输出(应该首先完成此操作)

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
...
Run Code Online (Sandbox Code Playgroud)

Gra*_*ray 11

我的问题是:为什么民意调查比迭代更快?这对我来说完全不直观,因为poll必须修改队列,迭代只需要查看状态.

正如@csoroiu指出的那样,这似乎是一个热点编译问题.鉴于Java的工作原理,在开始像这样的定时调用之前,"预热"应用程序是非常重要的.

如果我在一个方法中运行你的测试100次,我最初看到由于GC开销和其他JVM魔法而导致的性能差异很大.但是,在添加一些.clear()方法和方法System.gc()结束后,性能数字与迭代器获胜更加一致:

108 143
89 152
83 148
78 140
79 153
90 155
...
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请参阅Peter的答案:Java中的CPU执行时间

有关如何正确进行这样的微基准测试的更多信息,请参阅这个详尽的答案:如何在Java中编写正确的微基准测试?