In Bezug auf die Leistung, skipList
wenn als Map verwendet wird - scheint, 10-20 Mal langsamer sein. Hier ist das Ergebnis meiner Tests (Java 1.8.0_102-b14 gewinnen x32)
Benchmark Mode Cnt Score Error Units
MyBenchmark.hasMap_get avgt 5 0.015 ? 0.001 s/op
MyBenchmark.hashMap_put avgt 5 0.029 ? 0.004 s/op
MyBenchmark.skipListMap_get avgt 5 0.312 ? 0.014 s/op
MyBenchmark.skipList_put avgt 5 0.351 ? 0.007 s/op
Und zusätzlich zu, dass - verwendungs Fall, in dem Vergleich eine Eins-zu-ein anderer wirklich Sinn macht. Implementierung des Caches der zuletzt verwendeten Elemente unter Verwendung dieser beiden Sammlungen. Die Effizienz von skipList scheint nun zweifelhafter zu sein. Hier
MyBenchmark.hashMap_put1000_lru avgt 5 0.032 ? 0.001 s/op
MyBenchmark.skipListMap_put1000_lru avgt 5 3.332 ? 0.124 s/op
ist der Code für JMH (ausgeführt als java -jar target/benchmarks.jar -bm avgt -f 1 -wi 5 -i 5 -t 1
)
static final int nCycles = 50000;
static final int nRep = 10;
static final int dataSize = nCycles/4;
static final List<String> data = new ArrayList<>(nCycles);
static final Map<String,String> hmap4get = new ConcurrentHashMap<>(3000, 0.5f, 10);
static final Map<String,String> smap4get = new ConcurrentSkipListMap<>();
static {
// prepare data
List<String> values = new ArrayList<>(dataSize);
for(int i = 0; i < dataSize; i++) {
values.add(UUID.randomUUID().toString());
}
// rehash data for all cycles
for(int i = 0; i < nCycles; i++) {
data.add(values.get((int)(Math.random() * dataSize)));
}
// rehash data for all cycles
for(int i = 0; i < dataSize; i++) {
String value = data.get((int)(Math.random() * dataSize));
hmap4get.put(value, value);
smap4get.put(value, value);
}
}
@Benchmark
public void skipList_put() {
for(int n = 0; n < nRep; n++) {
Map<String,String> map = new ConcurrentSkipListMap<>();
for(int i = 0; i < nCycles; i++) {
String key = data.get(i);
map.put(key, key);
}
}
}
@Benchmark
public void skipListMap_get() {
for(int n = 0; n < nRep; n++) {
for(int i = 0; i < nCycles; i++) {
String key = data.get(i);
smap4get.get(key);
}
}
}
@Benchmark
public void hashMap_put() {
for(int n = 0; n < nRep; n++) {
Map<String,String> map = new ConcurrentHashMap<>(3000, 0.5f, 10);
for(int i = 0; i < nCycles; i++) {
String key = data.get(i);
map.put(key, key);
}
}
}
@Benchmark
public void hasMap_get() {
for(int n = 0; n < nRep; n++) {
for(int i = 0; i < nCycles; i++) {
String key = data.get(i);
hmap4get.get(key);
}
}
}
@Benchmark
public void skipListMap_put1000_lru() {
int sizeLimit = 1000;
for(int n = 0; n < nRep; n++) {
ConcurrentSkipListMap<String,String> map = new ConcurrentSkipListMap<>();
for(int i = 0; i < nCycles; i++) {
String key = data.get(i);
String oldValue = map.put(key, key);
if((oldValue == null) && map.size() > sizeLimit) {
// not real lru, but i care only about performance here
map.remove(map.firstKey());
}
}
}
}
@Benchmark
public void hashMap_put1000_lru() {
int sizeLimit = 1000;
Queue<String> lru = new ArrayBlockingQueue<>(sizeLimit + 50);
for(int n = 0; n < nRep; n++) {
Map<String,String> map = new ConcurrentHashMap<>(3000, 0.5f, 10);
lru.clear();
for(int i = 0; i < nCycles; i++) {
String key = data.get(i);
String oldValue = map.put(key, key);
if((oldValue == null) && lru.size() > sizeLimit) {
map.remove(lru.poll());
lru.add(key);
}
}
}
}
Ok. Log (n) ist in Ordnung, aber ist ConcurrentSkipListMap platzsparend? – DKSRathore
Skip-Listen sind notwendigerweise größer als Hashtables, aber die einstellbare Natur von ConcurrentHashMap ermöglicht es, eine Hashtable zu erstellen, die größer als die entsprechende ConcurrentSkipListMap ist. Im Allgemeinen würde ich erwarten, dass die Skip-Liste größer, aber in der gleichen Größenordnung ist. –
"Es unterstützt auch nicht die Abstimmung für die Gleichzeitigkeit". Warum? Was ist die Verbindung? – Pacerier