From 3cb3f304df163af4a46cb519dd204108341711f2 Mon Sep 17 00:00:00 2001 From: godotg Date: Tue, 2 Jul 2024 15:10:57 +0800 Subject: [PATCH] perf[hashmap]: ConcurrentHashMapLongObject equals and hashcode --- .../ConcurrentHashMapLongObject.java | 47 +++++++++++- .../collection/ConcurrentHashMapTest.java | 73 +++++++++++++++++++ .../collection/ConcurrentTesting.java | 51 ------------- 3 files changed, 117 insertions(+), 54 deletions(-) create mode 100644 protocol/src/test/java/com/zfoo/protocol/collection/ConcurrentHashMapTest.java diff --git a/protocol/src/main/java/com/zfoo/protocol/collection/concurrent/ConcurrentHashMapLongObject.java b/protocol/src/main/java/com/zfoo/protocol/collection/concurrent/ConcurrentHashMapLongObject.java index 3aba82c7..c59ca0fa 100644 --- a/protocol/src/main/java/com/zfoo/protocol/collection/concurrent/ConcurrentHashMapLongObject.java +++ b/protocol/src/main/java/com/zfoo/protocol/collection/concurrent/ConcurrentHashMapLongObject.java @@ -191,20 +191,61 @@ public class ConcurrentHashMapLongObject implements Map { } } + private Map copyMap() { + var copyMap = new HashMap(); + for (var i = 0; i < buckets; i++) { + var readLock = locks[i].readLock(); + var map = maps.get(i); + readLock.lock(); + try { + copyMap.putAll(map); + } finally { + readLock.unlock(); + } + } + return copyMap; + } + @Override public Set keySet() { - throw new UnsupportedOperationException(); + return copyMap().keySet(); } @Override public Collection values() { - throw new UnsupportedOperationException(); + return copyMap().values(); } @Override public Set> entrySet() { - throw new UnsupportedOperationException(); + return copyMap().entrySet(); } + @Override + public boolean equals(Object o) { + if (!(o instanceof Map m)) { + return false; + } + if (m.size() != size()) { + return false; + } + + for (var entry : m.entrySet()) { + var key = entry.getKey(); + var value = entry.getValue(); + if (!containsKey(key)) { + return false; + } + if (!Objects.equals(value, get(key))) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return super.hashCode(); + } } diff --git a/protocol/src/test/java/com/zfoo/protocol/collection/ConcurrentHashMapTest.java b/protocol/src/test/java/com/zfoo/protocol/collection/ConcurrentHashMapTest.java new file mode 100644 index 00000000..32cfb53e --- /dev/null +++ b/protocol/src/test/java/com/zfoo/protocol/collection/ConcurrentHashMapTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.collection; + +import com.zfoo.protocol.collection.concurrent.ConcurrentHashMapLongObject; +import com.zfoo.protocol.collection.concurrent.CopyOnWriteHashMap; +import com.zfoo.protocol.collection.concurrent.CopyOnWriteHashMapLongObject; +import io.netty.util.collection.LongObjectHashMap; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Map; + +/** + * @author godotg + */ +public class ConcurrentHashMapTest { + + @Test + public void equalsMapTest() { + var map = Map.of(1L, "a", 2L, "b", 3L, "c"); + + var concurrentHashMapLongObject = new ConcurrentHashMapLongObject(); + concurrentHashMapLongObject.putAll(map); + Assert.assertEquals(map, concurrentHashMapLongObject); + + var copyOnWriteHashMap = new CopyOnWriteHashMap(); + copyOnWriteHashMap.putAll(map); + Assert.assertEquals(map, copyOnWriteHashMap); + + var copyOnWriteHashMapLongObject = new CopyOnWriteHashMapLongObject(); + copyOnWriteHashMapLongObject.putAll(map); + Assert.assertEquals(map, concurrentHashMapLongObject); + } + + @Test + public void primitiveMapTest() { + var map = new LongObjectHashMap(); + var startTime = System.currentTimeMillis(); + + var num = 10; + + for (int i = 0; i < 100; i++) { + for (int j = 0; j < num; j++) { + map.put(j, j); + } + for (var entry : map.entrySet()) { + var key = entry.getKey(); + var value = entry.getValue(); + } + for (int j = 0; j < num; j++) { + var value = (int) map.get((long) j); + Assert.assertEquals(value, j); + } + for (int j = 0; j < num; j++) { + map.remove((long) j); + } + } + + System.out.println(System.currentTimeMillis() - startTime); + } + +} diff --git a/protocol/src/test/java/com/zfoo/protocol/collection/ConcurrentTesting.java b/protocol/src/test/java/com/zfoo/protocol/collection/ConcurrentTesting.java index 535dc570..8889190f 100644 --- a/protocol/src/test/java/com/zfoo/protocol/collection/ConcurrentTesting.java +++ b/protocol/src/test/java/com/zfoo/protocol/collection/ConcurrentTesting.java @@ -233,55 +233,4 @@ public class ConcurrentTesting { System.out.println(atomicCount.get()); } - - // ----------------------------------------------------------------------------------------------------------------- - @Test - public void primitiveMapTest() { - var map = new LongObjectHashMap(); - var startTime = System.currentTimeMillis(); - - for (int count = 0; count < maxCount; count++) { - for (int j = 0; j < num; j++) { - map.put(j, j); - } - for (var entry : map.entrySet()) { - var key = entry.getKey(); - var value = entry.getValue(); - } - for (int j = 0; j < num; j++) { - var value = (int) map.get((long) j); - Assert.assertEquals(value, j); - } - for (int j = 0; j < num; j++) { - map.remove((long) j); - } - } - - System.out.println(System.currentTimeMillis() - startTime); - } - - @Test - public void mapTest() { - var map = new HashMap(); - var startTime = System.currentTimeMillis(); - - for (int count = 0; count < maxCount; count++) { - for (int j = 0; j < num; j++) { - map.put((long) j, j); - } - for (var entry : map.entrySet()) { - var key = entry.getKey(); - var value = entry.getValue(); - } - for (int j = 0; j < num; j++) { - var value = (int) map.get((long) j); - Assert.assertEquals(value, j); - } - for (int j = 0; j < num; j++) { - map.remove((long) j); - } - } - - System.out.println(System.currentTimeMillis() - startTime); - } }