java - Vector 的填充时间比 ArrayList 少

标签 java arraylist vector collections

我正在阅读以下文章:

Understanding Collections and Thread Safety in Java

文章说:

You know, Vector and Hashtable are the two collections exist early in Java history, and they are designed for thread-safe from the start (if you have chance to look at their source code, you will see their methods are all synchronized!). However, they quickly expose poor performance in multi-threaded programs. As you may know, synchronization requires locks which always take time to monitor, and that reduces the performance.

[我还使用 Caliper 进行了基准测试;请听我说完]

还提供了示例代码:

public class CollectionsThreadSafeTest {

    public void testVector() {
        long startTime = System.currentTimeMillis();

        Vector<Integer> vector = new Vector<>();
        for (int i = 0; i < 10_000_000; i++) {
            vector.addElement(i);
        }

        long endTime = System.currentTimeMillis();
        long totalTime = endTime - startTime;
        System.out.println("Test Vector: " + totalTime + " ms");
    }

    public void testArrayList() {
        long startTime = System.currentTimeMillis();

        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10_000_000; i++) {
            list.add(i);
        }

        long endTime = System.currentTimeMillis();
        long totalTime = endTime - startTime;
        System.out.println("Test ArrayList: " + totalTime + " ms");
    }

    public static void main(String[] args) {
        CollectionsThreadSafeTest tester = new CollectionsThreadSafeTest();

        tester.testVector();
        tester.testArrayList();
    }
}

他们为上述代码提供的输出如下:

Test Vector: 9266 ms
Test ArrayList: 4588 ms

但是当我在我的机器上运行它时,它给出了以下结果:

Test Vector: 521 ms
Test ArrayList: 2273 ms

我发现这很奇怪。我认为进行微基准测试会更好。因此,我使用卡尺为上述内容编写了一个基准测试。代码如下:

public class CollectionsThreadSafeTest extends SimpleBenchmark {

    public static final int ELEMENTS = 10_000_000;

    public void timeVector(int reps) {
        for (int i = 0; i < reps; i++) {
            Vector<Integer> vector = new Vector<>();
            for (int k = 0; k < ELEMENTS; k++) {
                vector.addElement(k);
            }
        }
    }

    public void timeArrayList(int reps) {
        for (int i = 0; i < reps; i++) {
            List<Integer> list = new ArrayList<>();
            for (int k = 0; k < ELEMENTS; k++) {
                list.add(k);
            }
        }
    }

    public static void main(String[] args) {
        String[] classesToTest = { CollectionsThreadSafeTest.class.getName() };
        Runner.main(classesToTest);
    }
}

但我得到了类似的结果:

 0% Scenario{vm=java, trial=0, benchmark=ArrayList} 111684174.60 ns; ?=18060504.25 ns @ 10 trials
50% Scenario{vm=java, trial=0, benchmark=Vector} 67701359.18 ns; ?=17924728.23 ns @ 10 trials

benchmark    ms linear runtime
ArrayList 111.7 ==============================
   Vector  67.7 ==================

vm: java
trial: 0

我有点困惑。这里发生了什么?我在这里做错了什么吗(这真的很尴尬)?

如果这是预期的行为,那么这背后的解释是什么?


更新#1

阅读后@Kayamananswer ,我通过更改 VectorArrayList 的初始容量值来运行卡尺测试。以下是时间(以毫秒为单位):

Initial Capacity    Vector  ArrayList
-------------------------------------
10_000_000          49.2    67.1
10_000_001          48.9    71.2
10_000_010          48.1    61.2
10_000_100          43.9    70.1
10_001_000          45.6    70.6
10_010_000          44.8    68.0
10_100_000          52.8    64.6
11_000_000          52.7    71.7
20_000_000          74.0    51.8
-------------------------------------

感谢您的所有投入:)

最佳答案

您并没有真正在此处测试 add() 方法。您正在测试 VectorArrayList 增长的不同方式。 Vector 填满时大小会加倍,但 ArrayList 有一些更精细的逻辑来防止内部数组呈指数增长并浪费内存。

如果您使用两个类的初始容量 > 10000000 来运行测试,则它们不需要调整大小,您只需分析添加部分。

关于java - Vector 的填充时间比 ArrayList 少,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43602273/

相关文章:

java - 如何计算考虑到日节省类次的日期之间的天数?

java - 单击删除按钮时,android从数组列表中删除值

python - 比较向量列表

vector - Rust 中向量的元素如何左移?

java - 在java中打印文本文件中的输出

C++ vector 和结构体问题 win32

java - 代码不会输出输入的内容,也不会计算输入的数字

java - 选项卡式 Activity 中未显示工具栏标题

java - 扩展配置器中的 Spring Boot @Autowired null

java - 如何将类型传递给 java 中的泛型类?