我正在阅读以下文章:
Understanding Collections and Thread Safety in Java
文章说:
你知道,Vector和Hashtable是Java历史早期存在的两个集合,它们从一开始就设计用于线程安全(如果你有机会查看它们的源代码,你会发现它们的方法都是同步的!)。但是,它们很快就会在多线程程序中暴露出糟糕的性能。您可能知道,同步需要锁,这些锁总是需要时间来监控,这会降低性能。
[我也使用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
我发现这很奇怪。我认为做微观基准会更好。所以,我用caliper为上面写了一个基准。代码如下:
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
在阅读@Kayaman的answer后,我通过更改Vector
和ArrayList
的初始容量值来运行卡尺测试。以下是时间(毫秒):
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
-------------------------------------
感谢所有输入:)
答案 0 :(得分:3)
这里你并没有真正测试add()
方法。您正在测试Vector
和ArrayList
增长的不同方式。当Vector
已满时,ArrayList
的大小会翻倍,但library(dplyr)
f2a <- c(1,0,0,1)
f2b <- c(0,0,0,1)
f2c <- c(1,1,1,1)
clustervar <- c("A","B","B","A")
weight <- c(10,20,30,40)
df <- data.frame (f2a, f2b, f2c, clustervar, weight, stringsAsFactors=FALSE)
df
会有一些更精确的逻辑,以防止内部数组以指数方式增长并浪费内存。
如果您使用&gt;运行测试这两个类的初始容量为10000000,它们不需要调整大小,您只需要分析添加部分。
答案 1 :(得分:0)
在多线程环境中,矢量预计会变慢。在您的情况下,它应该是轻量级的。最好通过从10000个不同的线程中添加这些项来进行测试
答案 2 :(得分:-1)
ArrayList和Vector都有相同的添加方法:
ensureCapacity();
elementData[elementCount++] = newElement;
差异只有一个。 Vector的add方法是同步的,而ArrayList则不是。理论上,同步方法比非同步方法慢。
要提高add方法的性能,您必须在构造函数中指定initialCapacity
或调用方法ensureCapacity
。只要您需要,就可以创建内部数组,因此无需重新创建它。