finalアリ/ナシでの処理時間差と謎現象

気になったので、フィールドにfinalアリ/ナシでメソッド呼び出しに差がでるかどうか確認してみました。
まあ、結論としてはどっちも一緒、なんですけど、ちょっと謎現象がありました。


インタフェースのフィールドとクラスのフィールドそれぞれfinalアリ・ナシで
リストは最後に。


結果こんな感じ。

warming up:36ms
Interface Non Final:26ms
-- first -- 
Interface Final:50ms
Interface Non Final:44ms
Class Final:44ms
Class Non Final:41ms
-- second --
Interface Final:40ms
Interface Non Final:38ms
Class Final:40ms
Class Non Final:41ms


不思議なのは、ウォームアップ後の一回目はめちゃくちゃ速くなってるというところ。
これ、どれを最初にもってきても似たような数字になります。
というか、4つとも呼び出してるウォームアップが速いなー。
何が起こってるんだろう?

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class FinalBench {
	private static class InterfaceFinal{
		private final List<String> list;

		public InterfaceFinal(List<String> list) {
			this.list = list;
		}

		public void proc(){
			list.set(0, "123");
		}
	}
	private static class InterfaceNonFinal{
		private List<String> list;

		public void setList(List<String> list) {
			this.list = list;
		}
		public void proc(){
			list.set(0, "123");
		}
	}
	private static class ClassFinal{
		private final ArrayList<String> list;

		public ClassFinal(ArrayList<String> list) {
			this.list = list;
		}

		public void proc(){
			list.set(0, "123");
		}
	}
	private static class ClassNonFinal{
		private ArrayList<String> list;

		public void setList(ArrayList<String> list) {
			this.list = list;
		}
		public void proc(){
			list.set(0, "123");
		}
	}
	public static void main(String[] args) {
		ClassFinal cf = new ClassFinal((ArrayList<String>) Stream.of("123").collect(Collectors.toList()));
		ClassNonFinal cnf = new ClassNonFinal();
		cnf.setList((ArrayList<String>) Stream.of("123").collect(Collectors.toList()));
		InterfaceFinal iff = new InterfaceFinal((ArrayList<String>) Stream.of("123").collect(Collectors.toList()));
		InterfaceNonFinal ifnf = new InterfaceNonFinal();
		ifnf.setList((ArrayList<String>) Stream.of("123").collect(Collectors.toList()));

		bench("warming up", () -> {
			cf.proc();
			cnf.proc();
			iff.proc();
			ifnf.proc();
		});
		bench("Interface Non Final", cnf::proc);
		System.out.println("-- first -- ");
		bench("Interface Final", cf::proc);
		bench("Interface Non Final", cnf::proc);
		bench("Class Final", iff::proc);
		bench("Class Non Final", ifnf::proc);

		System.out.println("-- second --");
		bench("Interface Final", cf::proc);
		bench("Interface Non Final", cnf::proc);
		bench("Class Final", iff::proc);
		bench("Class Non Final", ifnf::proc);

	}

	static void bench(String name, Runnable proc){
		for(int i = 0; i < 100; ++i){
			proc.run();
		}
		long start = System.currentTimeMillis();
		for(int i = 0; i < 10_000_000; ++i){
			proc.run();
		}
		System.out.printf("%s:%dms%n", name, System.currentTimeMillis() - start);
	}

}