Java映射同步
我正在做一件我定义了Collections.synchronizedMap的事情 在一个线程A中,它将只获取值,并放入一个更新的值,这样就不会出现问题 在另一个线程B中,它将遍历条目,然后根据条目的值进行比较,如果它符合某些条件,它将从映射中删除该条目 我的理解是,同步地图将阻止访问Java映射同步,java,multithreading,synchronization,synchronized,Java,Multithreading,Synchronization,Synchronized,我正在做一件我定义了Collections.synchronizedMap的事情 在一个线程A中,它将只获取值,并放入一个更新的值,这样就不会出现问题 在另一个线程B中,它将遍历条目,然后根据条目的值进行比较,如果它符合某些条件,它将从映射中删除该条目 我的理解是,同步地图将阻止访问 但是有没有可能线程B获取一个条目,然后线程A更新该值,然后线程B删除该值,因为它符合某些条件,但它不应该有,因为线程A将其更新为的值。解决这个问题的最佳实现是什么?听起来您只需要同步“获取、检查和删除”部分。例如:
但是有没有可能线程B获取一个条目,然后线程A更新该值,然后线程B删除该值,因为它符合某些条件,但它不应该有,因为线程A将其更新为的值。解决这个问题的最佳实现是什么?听起来您只需要同步“获取、检查和删除”部分。例如:
Iterable<String> keys;
synchronized (map) {
keys = new ArrayList<>(map.keySet());
}
for (String key : keys) {
synchronized (map) {
Integer value = map.get(key);
// The other thread won't be able to update the value at this point
if (value != null && value < 0) {
map.remove(key);
}
}
}
Iterable键;
同步(地图){
keys=newarraylist(map.keySet());
}
用于(字符串键:键){
同步(地图){
整数值=map.get(键);
//另一个线程此时将无法更新该值
如果(值!=null&&value<0){
地图。删除(键);
}
}
}
您的更新线程可能需要做同样的事情-从您的描述中不清楚它是否需要“查看”删除。听起来您只需要同步“获取、检查和删除”部分。例如:
Iterable<String> keys;
synchronized (map) {
keys = new ArrayList<>(map.keySet());
}
for (String key : keys) {
synchronized (map) {
Integer value = map.get(key);
// The other thread won't be able to update the value at this point
if (value != null && value < 0) {
map.remove(key);
}
}
}
Iterable键;
同步(地图){
keys=newarraylist(map.keySet());
}
用于(字符串键:键){
同步(地图){
整数值=map.get(键);
//另一个线程此时将无法更新该值
如果(值!=null&&value<0){
地图。删除(键);
}
}
}
您的更新线程可能需要做同样的事情-从您的描述中不清楚是否需要“查看”删除。您还需要同步正在使用映射的代码块 请看这里:
您还需要同步正在使用映射的代码块 请看这里:
听起来您好像在尝试实现缓存。有很多好的并发缓存实现。我相信它有一个相当不错的实现。听起来你在尝试实现缓存。有很多好的并发缓存实现。我相信它有一个相当不错的实现。这可以完全不用像这样使用
final ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>(); // creation
map.put("aKey", "aValue"); // example content
// Thread A:
map.replace("aKey", "aNewValue"); // atomic replace call
// Thread B:
for (String key : map.keySet()) {
do {
processed = true;
final String value = map.get(key);
if ((value != null) && shouldRemove(value)) { // some comparison or check
if (map.remove("aKey", value) == false) { // is value still the same?
processed = false; // value has been changed in between, try again
}
}
} while (processed == false);
}
final ConcurrentHashMap=new ConcurrentHashMap();//创造
map.put(“aKey”、“aValue”);//示例内容
//线程A:
映射。替换(“aKey”、“aNewValue”);//原子替换调用
//线程B:
for(字符串键:map.keySet()){
做{
已处理=真;
最终字符串值=map.get(键);
如果((value!=null)&&shouldRemove(value)){//进行一些比较或检查
如果(map.remove(“aKey”,value)==false){//值是否仍然相同?
processed=false;//值在这段时间内已更改,请重试
}
}
}while(processed==false);
}
这是线程安全的,因为线程B只会删除值(原子性地),如果在这两个值之间没有更改的话。如果在这两个值之间发生了更改,线程B将重试并使用新值进行比较。这与其他原子类中使用的compareAndSet
的概念类似
如果线程A很少更改,那么线程B将以与未同步映射几乎相同的速度执行。如果线程A做了很多更改,那么线程B中可能会有几个重复调用,这取决于执行比较所需的时间以及值更改的频率。但在所有情况下,这都是线程安全的,比任何同步实现都要快。这完全可以在不阻塞的情况下完成,使用如下方法:
final ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>(); // creation
map.put("aKey", "aValue"); // example content
// Thread A:
map.replace("aKey", "aNewValue"); // atomic replace call
// Thread B:
for (String key : map.keySet()) {
do {
processed = true;
final String value = map.get(key);
if ((value != null) && shouldRemove(value)) { // some comparison or check
if (map.remove("aKey", value) == false) { // is value still the same?
processed = false; // value has been changed in between, try again
}
}
} while (processed == false);
}
final ConcurrentHashMap=new ConcurrentHashMap();//创造
map.put(“aKey”、“aValue”);//示例内容
//线程A:
映射。替换(“aKey”、“aNewValue”);//原子替换调用
//线程B:
for(字符串键:map.keySet()){
做{
已处理=真;
最终字符串值=map.get(键);
如果((value!=null)&&shouldRemove(value)){//进行一些比较或检查
如果(map.remove(“aKey”,value)==false){//值是否仍然相同?
processed=false;//值在这段时间内已更改,请重试
}
}
}while(processed==false);
}
这是线程安全的,因为线程B只会删除值(原子性地),如果在这两个值之间没有更改的话。如果在这两个值之间发生了更改,线程B将重试并使用新值进行比较。这与其他原子类中使用的compareAndSet
的概念类似
如果线程A很少更改,那么线程B将以与未同步映射几乎相同的速度执行。如果线程A做了很多更改,那么线程B中可能会有几个重复调用,这取决于执行比较所需的时间以及值更改的频率。但在所有情况下,这都是线程安全的,比任何同步实现都要快。首先介绍解决方案。我认为最好的解决方案是标准的ConcurrentHashMap。它具有如下移除的CAS操作:
boolean remove(Object key, Object value)
Removes the entry for a key only if currently mapped to a given value.
希望能有帮助
现在,第二件事是关于“我的理解是,同步映射将阻止访问。”我认为这不是完全的理解,请参见以下同步映射javadoc的详细信息:
* It is imperative that the user manually synchronize on the returned
* map when iterating over any of its collection views:
* <pre>
* Map m = Collections.synchronizedMap(new HashMap());
* ...
* Set s = m.keySet(); // Needn't be in synchronized block
* ...
* synchronized (m) { // Synchronizing on m, not s!
* Iterator i = s.iterator(); // Must be in synchronized block
* while (i.hasNext())
* foo(i.next());
* }
* </pre>
*用户必须手动同步返回的
*在其任何集合视图上迭代时映射:
*
*Map m=Collections.synchronizedMap(新的HashMap());
* ...
*设置s=m.keySet();//不必在同步块中
* ...
*已同步(m){//在m上同步,而不是在s上同步!
*迭代器i=s.Iterator();//必须在同步块中
*while(i.hasNext())
*foo(i.next());
* }
*