cae*_*kim 4 java data-structures
我知道Hashtable是同步的,所以在多线程应用程序中使用它是安全的,而HashMap不是。
我想知道在单线程应用程序中这两者之间是否有任何性能差异。
(或者,什么时候使用一个而不是另一个?)
如果你想要一个线程安全的集合,你可以将 ConcurrentHashMap 或 Collections.synchronizedMap() 与 LinkedHashMap 或 HashMap 一起使用。如果您不需要线程安全集合,您可以只使用最后两个。Hashtable 已经被改造为支持带有泛型的 Map,但它也带有许多传统方法,它们可以做同样的事情或几乎相同的事情。
可以使用哈希表,但是恕我直言,使用后来开发的许多其他选项之一将是一个更清洁的解决方案。如果您有一个需要 Hashtable 的库,那么您需要使用它,否则我将使用一个可以满足您需求的类,并遵循最佳实践并使用最少的遗留方法。
每次调用的性能差异可能约为 0.5 us。这可能重要也可能不重要。
但是,如果您不需要类型是线程安全的,则没有充分的理由使用同步版本。如果你需要一个类型是线程安全的,你不能使用一个不是没有一些线程安全保护的类型。
小智 5
这里有一些单线程测试来比较它们。100 次磨机操作中的 5 次尝试(第一次尝试可能被视为热身)放置是 100% 碰撞,获取是 50% 命中。
1 HashMap put/get --> 419.80 / 354.09 ms
2 HashMap put/get --> 983.02 / 305.54 ms
3 HashMap put/get --> 976.26 / 358.72 ms
4 HashMap put/get --> 989.04 / 375.18 ms
5 HashMap put/get --> 974.13 / 360.73 ms
1 Hashtable put/get --> 776.97 / 708.39 ms
2 Hashtable put/get --> 776.26 / 736.23 ms
3 Hashtable put/get --> 794.01 / 740.07 ms
4 Hashtable put/get --> 784.23 / 734.40 ms
5 Hashtable put/get --> 782.45 / 729.48 ms
1 Synced-HashMap put/get --> 1523.61 / 1215.63 ms
2 Synced-HashMap put/get --> 1491.59 / 1090.83 ms
3 Synced-HashMap put/get --> 1442.67 / 1095.62 ms
4 Synced-HashMap put/get --> 1439.19 / 1082.57 ms
5 Synced-HashMap put/get --> 1450.04 / 1101.53 ms
Run Code Online (Sandbox Code Playgroud)
用于测试的代码作为 JUnit:
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import org.junit.Test;
public class MapsPerfTest {
@Test
public void testMaps() {
testMap("HashMap", new HashMap<>());
testMap("Hashtable", new Hashtable<>());
testMap("Synced-HashMap", Collections.synchronizedMap(new HashMap<>()));
}
void testMap(String name, Map<Integer, String> h) {
for(int i=1; i<=tries; ++i) {
long t1 = timeit(() -> testMapPut(h));
long t2 = timeit(() -> testMapGet(h));
System.out.println(String.format("%d %s put/get --> %7.2f / %7.2f ms",
i, name, t1/1000/1000.0, t2/1000/1000.0));
}
}
long timeit(Runnable r) {
System.gc();
long t = System.nanoTime();
r.run();
return System.nanoTime() - t;
}
static final int tries = 5;
static final int count = 100000000;
static final String VALUE = "-";
static final int putSpace = 100;
static final int getSpace = putSpace*2;
static final Integer[] numbers = new Integer[getSpace+1];
static {
for(int i=getSpace; i>=0; --i)
numbers[i] = i;
}
void testMapPut(Map<Integer, String> m) {
for(int i=count; i>0; --i)
m.put(numbers[i%putSpace], VALUE);
}
void testMapGet(Map<Integer, String> m) {
for(int i=count; i>0; --i)
m.get(numbers[i%getSpace]);
}
}
Run Code Online (Sandbox Code Playgroud)
是的。这是 HashMap 默认情况下不同步的(其中之一)(使用 synchronizedMap() 使其同步;尽管请注意,根据您的使用情况,仅简单的同步可能不足以保持您可能想要的所有操作的完整性)做)。