Java 集合的并发映射-空时移除集合
我正在尝试用java编写一个线程安全的Map[K,Set[V]]实现Java 集合的并发映射-空时移除集合,java,concurrency,java.util.concurrent,Java,Concurrency,Java.util.concurrent,我正在尝试用java编写一个线程安全的Map[K,Set[V]]实现 如果将唯一键添加到地图中,则应创建一个新集(并将其添加到) 如果将非唯一密钥添加到地图中,则应将现有密钥集添加到地图中 如果从集合中删除某个值导致集合为空,则应从映射中删除该条目以避免内存泄漏 我想解决这个问题,而不需要同步整个事情 我在下面包含了一个失败的测试用例,如果您有解决方案,请告诉我 package org.deleteme; import java.util.ArrayList; import java.util
package org.deleteme;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import junit.framework.Assert;
import org.junit.Test;
public class ConcurrentSetMapTest {
public static class ConcurrentSetMap<K, V> {
private final ConcurrentMap<K, Set<V>> map = new ConcurrentHashMap<K, Set<V>>();
public void add(K key, V value) {
Set<V> set = map.get(key);
if (set != null) {
set.add(value);
} else {
Set<V> candidateSet = createConcurrentSet(value);
set = map.putIfAbsent(key, candidateSet);
if (set != null) {
// candidate set not accepted, use existing
set.add(value);
}
}
}
public void remove(K key, V value) {
Set<V> set = map.get(key);
if (set != null) {
boolean removed = set.remove(value);
if (removed && set.isEmpty()) {
// this is not thread-safe and causes the test to fail
map.remove(key, set);
}
}
}
public boolean contains(K key, V value) {
Set<V> set = map.get(key);
if (set == null) {
return false;
}
return set.contains(value);
}
protected Set<V> createConcurrentSet(V element) {
Set<V> set = Collections.newSetFromMap(new ConcurrentHashMap<V, Boolean>());
set.add(element);
return set;
}
}
@Test
public void testThreadSafe() throws InterruptedException, ExecutionException {
ConcurrentSetMap<String, String> setMap = new ConcurrentSetMap<String, String>();
ExecutorService executors = Executors.newFixedThreadPool(4);
List<Future<?>> futures = new ArrayList<Future<?>>();
futures.add(executors.submit(new TestWorker(setMap, "key1")));
futures.add(executors.submit(new TestWorker(setMap, "key1")));
futures.add(executors.submit(new TestWorker(setMap, "key2")));
futures.add(executors.submit(new TestWorker(setMap, "key2")));
for (Future<?> future : futures) {
future.get();
}
}
public static class TestWorker implements Runnable {
ConcurrentSetMap<String, String> setMap;
String key;
public TestWorker(ConcurrentSetMap<String, String> setMap, String key) {
super();
this.setMap = setMap;
this.key = key;
}
public void run() {
int sampleSize = 100000;
for (int i = 0; i < sampleSize; ++ i) {
// avoid value clashes with other threads
String value = Thread.currentThread().getName() + i;
Assert.assertFalse("Should not exist before add", setMap.contains(key, value));
setMap.add(key, value);
Assert.assertTrue("Should exist after add", setMap.contains(key, value));
setMap.remove(key, value);
Assert.assertFalse("Should not exist after remove", setMap.contains(key, value));
}
}
}
}
package org.deleteme;
导入java.util.ArrayList;
导入java.util.Collections;
导入java.util.List;
导入java.util.Set;
导入java.util.concurrent.ConcurrentHashMap;
导入java.util.concurrent.ConcurrentMap;
导入java.util.concurrent.ExecutionException;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.Future;
导入junit.framework.Assert;
导入org.junit.Test;
公共类ConcurrentSetMapTest{
公共静态类ConcurrentSetMap{
私有最终ConcurrentMap=新ConcurrentHashMap();
公共无效添加(K键,V值){
Set=map.get(键);
如果(设置!=null){
增加(价值);
}否则{
Set candidateSet=createConcurrentSet(值);
set=map.putIfAbsent(key,candidateSet);
如果(设置!=null){
//未接受候选集,请使用现有
增加(价值);
}
}
}
公共无效删除(K键,V值){
Set=map.get(键);
如果(设置!=null){
布尔删除=设置。删除(值);
if(已删除&set.isEmpty()){
//这不是线程安全的,会导致测试失败
地图。移除(键,集合);
}
}
}
公共布尔包含(K键,V值){
Set=map.get(键);
if(set==null){
返回false;
}
返回集合.contains(值);
}
受保护集createConcurrentSet(V元素){
Set=Collections.newSetFromMap(新的ConcurrentHashMap());
集合。添加(元素);
返回集;
}
}
@试验
public void testThreadSafe()引发InterruptedException、ExecutionException{
ConcurrentSetMap setMap=新的ConcurrentSetMap();
ExecutorService executors=executors.newFixedThreadPool(4);
列表>();
futures.add(executors.submit)(新的TestWorker(setMap,“key1”));
futures.add(executors.submit)(新的TestWorker(setMap,“key1”));
futures.add(executors.submit)(新的TestWorker(setMap,“key2”));
futures.add(executors.submit)(新的TestWorker(setMap,“key2”));
for(未来:未来){
future.get();
}
}
公共静态类TestWorker实现Runnable{
ConcurrentSetMap;
字符串键;
公共TestWorker(ConcurrentSetMap setMap,字符串键){
超级();
this.setMap=setMap;
this.key=key;
}
公开募捐{
int sampleSize=100000;
对于(int i=0;i
在执行多个操作时,需要使用锁定,这些操作需要是原子操作
public class SynchronousMultiMap<K, V> {
private final Map<K, Set<V>> map = new LinkedHashMap<K, Set<V>>();
public synchronized void add(K key, V value) {
Set<V> set = map.get(key);
if (set == null)
map.put(key, set = new LinkedHashSet<V>());
set.add(value);
}
public synchronized void remove(K key, V value) {
Set<V> set = map.get(key);
if (set == null) return;
set.remove(value);
if (set.isEmpty()) map.remove(key);
}
public synchronized boolean contains(K key, V value) {
Set<V> set = map.get(key);
return set != null && set.contains(value);
}
@Test
public void testThreadSafe() throws ExecutionException, InterruptedException {
ExecutorService executors = Executors.newFixedThreadPool(3);
List<Future<?>> futures = new ArrayList<Future<?>>();
SynchronousMultiMap<String, Integer> setMap = new SynchronousMultiMap<String, Integer>();
int sampleSize = 1000000;
String[] keys = "key1,key2,key3,key4".split(",");
for (int i = 0; i < 3; i++)
futures.add(executors.submit(new TestWorker(setMap, keys, sampleSize, i)));
executors.shutdown();
for (Future<?> future : futures) {
future.get();
}
}
static class TestWorker implements Runnable {
final SynchronousMultiMap<String, Integer> setMap;
final String[] keys;
final int sampleSize;
final int value;
public TestWorker(SynchronousMultiMap<String, Integer> setMap, String[] keys, int sampleSize, int value) {
super();
this.setMap = setMap;
this.keys = keys;
this.sampleSize = sampleSize;
this.value = value;
}
public void run() {
for (int i = 0; i < sampleSize; i += keys.length) {
for (String key : keys) {
boolean contains = setMap.contains(key, value);
if (contains)
Assert.assertFalse("Should not exist before add", contains);
setMap.add(key, value);
boolean contains2 = setMap.contains(key, value);
if (!contains2)
Assert.assertTrue("Should exist after add", contains2);
setMap.remove(key, value);
boolean contains3 = setMap.contains(key, value);
if (contains3)
Assert.assertFalse("Should not exist after remove", contains3);
}
}
}
}
}
公共类同步多重映射{
私有最终映射=新LinkedHashMap();
公共同步作废添加(K键,V值){
Set=map.get(键);
if(set==null)
put(key,set=newlinkedhashset());
增加(价值);
}
公共同步无效删除(K键,V值){
Set=map.get(键);
if(set==null)返回;
设置。删除(值);
if(set.isEmpty())map.remove(key);
}
公共同步布尔包含(K键,V值){
Set=map.get(键);
返回集!=null&&set.contains(值);
}
@试验
public void testThreadSafe()引发ExecutionException、InterruptedException{
ExecutorService executors=executors.newFixedThreadPool(3);
列表>();
SynchronousMultiMap setMap=新的SynchronousMultiMap();
int sampleSize=1000000;
字符串[]keys=“key1,key2,key3,key4”。拆分(“,”;
对于(int i=0;i<3;i++)
futures.add(executors.submit(newtestworker(setMap,key,sampleSize,i));
executors.shutdown();
for(未来:未来){
future.get();
}
}
静态类TestWorker实现Runnable{
最终同步多重映射集映射;
最终字符串[]键;
最终int样本化;
最终整数值;
公共TestWorker(SynchronousMultiMap setMap、字符串[]键、int-sampleSize、int-value){
超级();
this.setMap=setMap;
this.keys=keys;
this.sampleSize=sampleSize;
这个值=值;
}
公开募捐{
for(int i=0;ipublic class ConcurrentSetMap<K,V> {
private final ConcurrentMap<K, Set<V>> _map = new ConcurrentHashMap<K, Set<V>>();
public void add(K key, V value) {
Set<V> curSet = _map.get(key);
while(true) {
if((curSet != null) && curSet.contains(value)) {
break;
}
Set<V> newSet = new HashSet<V>();
newSet.add(value);
if(curSet == null) {
curSet = _map.putIfAbsent(key, newSet);
if(curSet != null) {
continue;
}
} else {
newSet.addAll(curSet);
if(!_map.replace(key, curSet, newSet)) {
curSet = _map.get(key);
continue;
}
}
break;
}
}
public void remove(K key, V value) {
Set<V> curSet = _map.get(key);
while(true) {
if((curSet == null) || !curSet.contains(value)) {
break;
}
if(curSet.size() == 1) {
if(!_map.remove(key, curSet)) {
curSet = _map.get(key);
continue;
}
} else {
Set<V> newSet = new HashSet<V>();
newSet.addAll(curSet);
newSet.remove(value);
if(!_map.replace(key, curSet, newSet)) {
curSet = _map.get(key);
continue;
}
}
break;
}
}
public boolean contains(K key, V value) {
Set<V> set = _map.get(key);
return set != null && set.contains(value);
}
}
public static class ConcurrentSetMap<K, V> {
private final ConcurrentMap<K, Set<V>> map = new ConcurrentHashMap<K, Set<V>>();
public synchronized void add(K key, V value) {
Set<V> set = map.get(key);
if (set != null) {
set.add(value);
} else {
map.put(key, createConcurrentSet(value));
}
}
public synchronized void remove(K key, V value) {
Set<V> set = map.get(key);
if (set != null) {
set.remove(value);
if (set.isEmpty()) {
map.remove(key);
}
}
}
public boolean contains(K key, V value) {
return get(key).contains(value);
}
public Set<V> get(K key) {
Set<V> set = map.get(key);
return set == null ? Collections.<V> emptySet() : set;
}
protected Set<V> createConcurrentSet(V value) {
Set<V> set = Collections.newSetFromMap(new ConcurrentHashMap<V, Boolean>());
set.add(value);
return set;
}
}