Java 同步写入两个集合
如果地图还不存在,我需要给它一些价值。键->值(如果设置)应始终位于两个集合中(即Java 同步写入两个集合,java,concurrency,atomicity,Java,Concurrency,Atomicity,如果地图还不存在,我需要给它一些价值。键->值(如果设置)应始终位于两个集合中(即put应在两个映射中原子地出现)。我已尝试通过以下方式实现这一点: private final ConcurrentMap<String, Object> map1 = new ConcurrentHashMap<String, Object>(); private final ConcurrentMap<String, Object> map2 = new Concurrent
put
应在两个映射中原子地出现)。我已尝试通过以下方式实现这一点:
private final ConcurrentMap<String, Object> map1 = new ConcurrentHashMap<String, Object>();
private final ConcurrentMap<String, Object> map2 = new ConcurrentHashMap<String, Object>();
public Object putIfAbsent(String key) {
Object retval = map1.get(key);
if (retval == null) {
synchronized (map1) {
retval = map1.get(key);
if (retval == null) {
Object value = new Object(); //or get it somewhere
synchronized (map2) {
map1.put(key, value);
map2.put(key, new Object());
}
retval = value;
}
}
}
return retval;
}
public void doSomething(String key) {
Object obj1 = map1.get(key);
Object obj2 = map2.get(key);
//do smth
}
private final ConcurrentMap map1=new ConcurrentHashMap();
私有最终ConcurrentMap map2=新ConcurrentHashMap();
公共对象putIfAbsent(字符串键){
Object retval=map1.get(key);
if(retval==null){
已同步(map1){
retval=map1.get(键);
if(retval==null){
Object value=new Object();//或者把它放到某个地方
已同步(map2){
map1.put(键、值);
map2.put(key,newobject());
}
retval=值;
}
}
}
返回返回;
}
公共void doSomething(字符串键){
对象obj1=map1.get(键);
对象obj2=map2.get(键);
//做smth
}
在所有情况下都可以吗?谢谢,有几个问题:
- 不要使用“双重检查锁定”。一个快速的谷歌搜索将显示大量的文章,解释这种技术的问题。只需检查
块内部synchronized
- 您不需要在
和map1
上同步。用一个或另一个map2
- 在
内同步。确保在doSomething
中用于同步的同一对象上进行同步putIfAbsent
- 不要使用“双重检查锁定”。一个快速的谷歌搜索将显示大量的文章,解释这种技术的问题。只需检查
块内部synchronized
- 您不需要在
和map1
上同步。用一个或另一个map2
- 在
内同步。确保在doSomething
中用于同步的同一对象上进行同步putIfAbsent
- 一些问题:
do {
oldValue1 = map1.get(key1);
oldValue2 = map2.get(key2);
newValue1 = // some logic to determine a new value for key1/value1
newValue2 = // some more logic to determine a new value for key2/value2
} while (!map1.replace(key1, oldValue1, newValue1) && !map2.replace(key2, oldValue2, newValue2));
我不知道如何具体地将其应用到您的示例中,但这应该给您一个开始的地方。基本上是从映射中获取密钥,执行一些逻辑,如果密钥仍然与逻辑之前相同,它将替换条目并返回true,那么循环将中断。否则,它只会重复循环,直到它能够以原子方式进行更新。您不应该使用synchronized with ConcurrentHashMap(这几乎违背了目的)。对CHH进行原子添加的最佳方法是使用内置的替换方法。例如:
do {
oldValue1 = map1.get(key1);
oldValue2 = map2.get(key2);
newValue1 = // some logic to determine a new value for key1/value1
newValue2 = // some more logic to determine a new value for key2/value2
} while (!map1.replace(key1, oldValue1, newValue1) && !map2.replace(key2, oldValue2, newValue2));
我不知道如何具体地将其应用到您的示例中,但这应该给您一个开始的地方。基本上是从映射中获取密钥,执行一些逻辑,如果密钥仍然与逻辑之前相同,它将替换条目并返回true,那么循环将中断。否则它只会重复循环,直到它能够以原子方式进行更新。为了完成您想要的操作,我将使用原子引用:
class PairHolder {
public final ConcurrentMap map1;
public final ConcurrentMap map2;
public PairHolder(...) // set values here.
}
private AtomicReference<PairHolder> mapHolder = ... // initialize it somehow
do {
PairHolder holder = mapHolder.get();
ConcurrentMap map1 = holder.map1.clone()
ConcurrentMap map2 = holder.map2.clone()
newMap1.putIfAbsent(...);
newMap2.putIfAbsent(...);
} while (!mapHolder.compareAndSet(holder, new PairHolder(newMap1,newMap2))
类配对器{
公共最终同意图map1;
公共最终同意图map2;
public PairHolder(…)//在此处设置值。
}
私有原子引用映射持有者=…//以某种方式初始化它
做{
PairHolder holder=mapHolder.get();
ConcurrentMap map1=holder.map1.clone()
ConcurrentMap map2=holder.map2.clone()
newMap1.putIfAbsent(…);
newMap2.putIfAbsent(…);
}而(!mapHolder.compareAndSet(holder,new PairHolder(newMap1,newMap2))
通过这种方式,您可以始终确保mapHolder包含对PairHolder的引用,而PairHolder又有两个映射以100%原子方式更新。至少CAS应该保证这一点,但在多处理器系统上,这可能是错误的。为了满足您的要求,我会使用原子引用:
class PairHolder {
public final ConcurrentMap map1;
public final ConcurrentMap map2;
public PairHolder(...) // set values here.
}
private AtomicReference<PairHolder> mapHolder = ... // initialize it somehow
do {
PairHolder holder = mapHolder.get();
ConcurrentMap map1 = holder.map1.clone()
ConcurrentMap map2 = holder.map2.clone()
newMap1.putIfAbsent(...);
newMap2.putIfAbsent(...);
} while (!mapHolder.compareAndSet(holder, new PairHolder(newMap1,newMap2))
类配对器{
公共最终同意图map1;
公共最终同意图map2;
public PairHolder(…)//在此处设置值。
}
私有原子引用映射持有者=…//以某种方式初始化它
做{
PairHolder holder=mapHolder.get();
ConcurrentMap map1=holder.map1.clone()
ConcurrentMap map2=holder.map2.clone()
newMap1.putIfAbsent(…);
newMap2.putIfAbsent(…);
}而(!mapHolder.compareAndSet(holder,new PairHolder(newMap1,newMap2))
通过这种方式,您可以始终确保mapHolder包含对PairHolder的引用,PairHolder又有两个映射100%原子更新。至少CAS应该保证这一点,但在多处理器系统上可能是错误的。好的,我终于找到了这个解决方案:
private Map<String, Object> map1 = new HashMap<String, Object>();
private Map<String, Object> map2 = new HashMap<String, Object>();
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
public void putIfAbsent(String key, Object o) {
rwl.readLock().lock();
try {
if (map1.get(key) == null) {
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
if (map1.get(key) == null) {
map1.put(key, getValue());
map2.put(key, getValue());
}
}finally {
rwl.readLock().lock();
rwl.writeLock().unlock();
}
}
} finally {
readLock.unlock();
}
}
public void readMap(String key) {
rwl.readLock().lock();
try {
Object obj1 = map1.get(key);
Object obj2 = map2.get(key);
} finally {
rwl.readLock().unlock();
}
}
private Map map1=new HashMap();
私有映射map2=新的HashMap();
private final ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();
public void putIfAbsent(字符串键,对象o){
rwl.readLock().lock();
试一试{
if(map1.get(key)==null){
rwl.readLock().unlock();
rwl.writeLock().lock();
试一试{
if(map1.get(key)==null){
map1.put(key,getValue());
map2.put(key,getValue());
}
}最后{
rwl.readLock().lock();
rwl.writeLock().unlock();
}
}
}最后{
readLock.unlock();
}
}
公共void readMap(字符串键){
rwl.readLock().lock();
试一试{
对象obj1=map1.get(键);
对象obj2=map2.get(键);
}最后{
rwl.readLock().unlock();
}
}
好的,我终于找到了这个解决方案:
private Map<String, Object> map1 = new HashMap<String, Object>();
private Map<String, Object> map2 = new HashMap<String, Object>();
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
public void putIfAbsent(String key, Object o) {
rwl.readLock().lock();
try {
if (map1.get(key) == null) {
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
if (map1.get(key) == null) {
map1.put(key, getValue());
map2.put(key, getValue());
}
}finally {
rwl.readLock().lock();
rwl.writeLock().unlock();
}
}
} finally {
readLock.unlock();
}
}
public void readMap(String key) {
rwl.readLock().lock();
try {
Object obj1 = map1.get(key);
Object obj2 = map2.get(key);
} finally {
rwl.readLock().unlock();
}
}
private Map map1=new HashMap();
私有映射map2=新的HashMap();
private final ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();
公共场所