簡體   English   中英

為什么Collections.synchronizedSet(HashSet)比HashSet對addAll,retainAll和contains更快?

[英]Why is Collections.synchronizedSet(HashSet) faster than HashSet for addAll, retainAll, and contains?

我運行了一個測試來找到我的程序的最佳並發Set實現,使用非同步的HashSet作為控件,並遇到了一個有趣的結果: addAllretainAllcontains Collections.synchronizedSet(HashSet)似乎比常規HashSet快。 我的理解是SynchronizedSet(HashSet)永遠不應該比HashSet更快,因為它由帶有同步鎖的HashSet組成。 我現在已經進行了幾次測試,結果相似。 難道我做錯了什么?

相關結果:

Testing set: HashSet
Add: 17.467758 ms
Retain: 28.865039 ms
Contains: 22.18998 ms
Total: 68.522777 ms
--
Testing set: SynchronizedSet
Add: 17.54269 ms
Retain: 20.173502 ms
Contains: 19.618188 ms
Total: 57.33438 ms

相關代碼:

public class SetPerformance {
    static Set<Long> source1 = new HashSet<>();
    static Set<Long> source2 = new HashSet<>();
    static Random rand = new Random();
    public static void main(String[] args) {
        Set<Long> control = new HashSet<>();
        Set<Long> synch = Collections.synchronizedSet(new HashSet<Long>());

        //populate sets to draw values from
        System.out.println("Populating source");
        for(int i = 0; i < 100000; i++) {
            source1.add(rand.nextLong());
            source2.add(rand.nextLong());
        }

        //populate sets with initial values
        System.out.println("Populating test sets");
        control.addAll(source1);
        synch.addAll(source1);

        testSet(control);
        testSet(synch);
    }

    public static void testSet(Set<Long> set) {
        System.out.println("--\nTesting set: " + set.getClass().getSimpleName());
        long start = System.nanoTime();
        set.addAll(source1);
        long add = System.nanoTime();
        set.retainAll(source1);
        long retain = System.nanoTime();
        boolean test;
        for(int i = 0; i < 100000; i++) {
            test = set.contains(rand.nextLong());
        }
        long contains = System.nanoTime();
        System.out.println("Add: " + (add - start) / 1000000.0 + " ms");
        System.out.println("Retain: " + (retain - add) / 1000000.0 + " ms");
        System.out.println("Contains: " + (contains - retain) / 1000000.0 + " ms");
        System.out.println("Total: " + (contains - start) / 1000000.0 + " ms");
    }
}

你沒有為JVM做准備。

請注意,您首先運行HashSet測試。

  1. 我稍微改變了你的程序,在循環中運行測試5次。 SynchronizedSet增快,我的機器上, 在第一次測試。
  2. 然后,我嘗試顛倒兩個測試的順序,只運行一次測試。 HashSet再次獲勝。

在這里閱讀更多相關內容: 如何在Java中編寫正確的微基准測試?

另外,請查看Google Caliper以獲取處理所有這些微基准測試問題的框架。

是嘗試在常規之前運行同步設置,您將獲得“所需”的結果。 我認為這與JVM熱身有關,沒有別的。 嘗試通過一些計算警告VM,然后運行基准測試或以混合順序運行幾次。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM