Пока вы выполняете все операции в одном вызове метода для одновременной хэш-карты, вам не нужно использовать дополнительную блокировку. К сожалению, если вам нужно выполнить несколько методов атомарно, вам придется использовать блокировку, и в этом случае использование параллельной карты хеша не помогает, и вы также можете использовать простой HashMap.
@ Предложение Джеймса заставило меня задуматься о том, ускоряет ли настройка ненужного параллелизма ConcurrentHashMap. Это должно уменьшить память, но вам нужно иметь тысячи таких, чтобы иметь большое значение. Поэтому я написал этот тест, и не кажется очевидным, что вам всегда нужно будет настраивать уровень параллелизма.
warmup: Average access time 36 ns.
warmup2: Average access time 28 ns.
1 concurrency: Average access time 25 ns.
2 concurrency: Average access time 25 ns.
4 concurrency: Average access time 25 ns.
8 concurrency: Average access time 25 ns.
16 concurrency: Average access time 24 ns.
32 concurrency: Average access time 25 ns.
64 concurrency: Average access time 26 ns.
128 concurrency: Average access time 26 ns.
256 concurrency: Average access time 26 ns.
512 concurrency: Average access time 27 ns.
1024 concurrency: Average access time 28 ns.
Код
public static void main(String[] args) {
test("warmup", new ConcurrentHashMap());
test("warmup2", new ConcurrentHashMap());
for(int i=1;i<=1024;i+=i)
test(i+" concurrency", new ConcurrentHashMap(16, 0.75f, i));
}
private static void test(String description, ConcurrentHashMap map) {
Integer[] ints = new Integer[2000];
for(int i=0;i<ints.length;i++)
ints[i] = i;
long start = System.nanoTime();
for(int i=0;i<20*1000*1000;i+=ints.length) {
for (Integer j : ints) {
map.put(j,1);
map.get(j);
}
}
long time = System.nanoTime() - start;
System.out.println(description+": Average access time "+(time/20/1000/1000/2)+" ns.");
}
Как указывает @bestss, больший уровень параллелизма может быть медленнее, поскольку он имеет более плохие характеристики кэширования.
РЕДАКТИРОВАТЬ: В дополнение к @betsss озабоченность по поводу того, оптимизируются ли циклы, если нет вызовов методов. Вот три цикла, все одинаковые, но повторяющиеся разное количество раз. Они печатают
10M: Time per loop 661 ps.
100K: Time per loop 26490 ps.
1M: Time per loop 19718 ps.
10M: Time per loop 4 ps.
100K: Time per loop 17 ps.
1M: Time per loop 0 ps.
.
{
int loops = 10*1000 * 1000;
long product = 1;
long start = System.nanoTime();
for(int i=0;i< loops;i++)
product *= i;
long time = System.nanoTime() - start;
System.out.println("10M: Time per loop "+1000*time/loops+" ps.");
}
{
int loops = 100 * 1000;
long product = 1;
long start = System.nanoTime();
for(int i=0;i< loops;i++)
product *= i;
long time = System.nanoTime() - start;
System.out.println("100K: Time per loop "+1000*time/loops+" ps.");
}
{
int loops = 1000 * 1000;
long product = 1;
long start = System.nanoTime();
for(int i=0;i< loops;i++)
product *= i;
long time = System.nanoTime() - start;
System.out.println("1M: Time per loop "+1000*time/loops+" ps.");
}
// code for three loops repeated