CurrentMap总结

本文详细介绍了ConcurrentHashMap,它是线程安全的Java Map,提供putIfAbsent、remove、replace方法,对比了与HashMap的区别,尤其强调了其Segment和HashEntry结构确保并发安全。

简单介绍CurrentHashMap

ConcurrentMap,它是一个接口,是一个能够支持并发访问的java.util.map集合;

ConcurrentHashMap是一个线程安全,并且是一个高效的HashMap。
spring 缓存注解 通过查看源代码发现将数据存在ConcurrentMap中

Map并发原理

  • ConcurrentMap
    • ConcurrentMap,它是一个接口,是一个能够支持并发访问的java.util.map集合;
    • 在原有java.util.map接口基础上又新提供了4种方法,进一步扩展了原有Map的功能:
    •  public interface ConcurrentMap<K, V> extends Map<K, V> {
      
      //插入元素
      V putIfAbsent(K key, V value);
      
      //移除元素
      boolean remove(Object key, Object value);
      
      //替换元素
      boolean replace(K key, V oldValue, V newValue);
      
      //替换元素
      V replace(K key, V value);
      }
      
      putIfAbsent:与原有put方法不同的是,putIfAbsent方法中如果插入的key相同,则不替换原有的value值;
      remove:与原有remove方法不同的是,新remove方法中增加了对value的判断,如果要删除的key--value不能与Map中原有的key--value对应上,则不会删除该元素;
      replace(K,V,V):增加了对value值的判断,如果key--oldValue能与Map中原有的key--value对应上,才进行替换操作;
      replace(K,V):与上面的replace不同的是,此replace不会对Map中原有的key--value进行比较,如果key存在则直接替换;
      
    • 其实,对于ConcurrentMap来说,我们更关注Map本身的操作,在并发情况下是如何实现数据安全的。在java.util.concurrent包中,ConcurrentMap的实现类主要以ConcurrentHashMap为主。接下来,我们具体来看下。
  • ConcurrentHashMap
    *ConcurrentHashMap是一个线程安全,并且是一个高效的HashMap。
    但是,如果从线程安全的角度来说,HashTable已经是一个线程安全的HashMap,那推出ConcurrentHashMap的意义又是什么呢?
    说起ConcurrentHashMap,就不得不先提及下HashMap在线程不安全的表现,以及HashTable的效率!
  • HashMap
    • 底层数据结构不一样,1.7是数组+链表,1.8则是数组+链表+红黑树结构(当链表长度大于8,转为红黑树)。
      JDK1.8中resize()方法在表为空时,创建表;在表不为空时,扩容;而JDK1.7中resize()方法负责扩容,inflateTable()负责创建表。
       1.8中没有区分键为null的情况,而1.7版本中对于键为null的情况调用putForNullKey()方法。但是两个版本中如果键为null,那么调用hash()方法得到的都将是0,所以键为null的元素都始终位于哈希表table【0】中。
      当1.8中的桶中元素处于链表的情况,遍历的同时最后如果没有匹配的,直接将节点添加到链表尾部;而1.7在遍历的同时没有添加数据,而是另外调用了addEntry()方法,将节点添加到链表头部。
      1.7中新增节点采用头插法,1.8中新增节点采用尾插法。这也是为什么1.8不容易出现环型链表的原因。
      1.7中是通过更改hashSeed值修改节点的hash值从而达到rehash时的链表分散,而1.8中键的hash值不会改变,rehash时根据(hash&oldCap)==0将链表分散。
       1.8rehash时保证原链表的顺序,而1.7中rehash时有可能改变链表的顺序(头插法导致)。
      在扩容的时候:1.7在插入数据之前扩容,而1.8插入数据成功之后扩容。
  • CurrentHashMap
    • 与HashMap不同的是,ConcurrentHashMap中多了一层数组结构,由Segment和HashEntry两个数组组成。其中Segment起到了加锁同步的作用,而HashEntry则起到了存储K.V键值对的作用。在ConcurrentHashMap中,每一个ConcurrentHashMap都包含了一个Segment数组,在Segment数组中每一个Segment对象则又包含了一个HashEntry数组,而在HashEntry数组中,每一个HashEntry对象保存K-V数据的同时又形成了链表结构,此时与HashMap结构相同。在多线程中,每一个Segment对象守护了一个HashEntry数组,当对ConcurrentHashMap中的元素修改时,在获取到对应的Segment数组角标后,都会对此Segment对象加锁,之后再去操作后面的HashEntry元素,这样每一个Segment对象下,都形成了一个小小的HashMap,在保证数据安全性的同时,又提高了同步的效率。只要不是操作同一个Segment对象的话,就不会出现线程等待的问题!
<think>好的,我现在需要帮助用户在Visual Studio 2019中使用IAOIBookmark和pActiveView.Extent来实现书签定位功能,并修改btnLocate_Click函数的源码。首先,我需要理解用户的需求以及他们提供的引用内容。 首先,用户提到他们之前可能使用了ISpatialBookmark,但现在想改用IAOIBookmark和pActiveView.Extent。我需要确认这两个接口的用途和区别。根据ArcGIS的文档,ISpatialBookmark通常用于存储空间书签,比如地图的范围或位置,而IAOIBookmark可能是指另一种类型的书签,可能和AOI(Area of Interest)相关。不过,可能用户在这里有拼写错误,正确的接口可能是IAOIBookmark,或者需要进一步确认。 接下来,查看用户提供的引用内容。引用[1]中提到了清除选择的操作,使用了IActiveView接口的ClearSelection和PartialRefresh方法。引用[2]是关于地图右键菜单获取选中要素的代码,涉及IMapControl2、ISelection等接口。引用[3]提到添加几个C++文件,可能与打印功能相关,但用户当前的问题是关于C#的书签定位,可能需要忽略这部分。 用户的目标是替换ISpatialBookmark为IAOIBookmark和pActiveView.Extent。首先需要确认IAOIBookmark是否存在,或者是否是指IBookmark接口。在ArcGIS的COM接口中,可能没有IAOIBookmark,但存在IBookmark接口,它有一个Locate方法,需要一个IActiveView参数。因此,可能用户想要使用IBookmark接口结合当前视图的范围来实现定位。 或者,用户可能希望将当前视图的范围保存为书签,然后通过书签定位回来。通常,使用ISpatialBookmark的Store方法保存当前范围,然后通过Locate方法恢复。如果用户想使用IActiveView的Extent属性来直接设置范围,可能不需要使用书签,而是直接操作Extent。 不过,根据用户的问题,他们希望用IAOIBookmark和pActiveView.Extent来替代ISpatialBookmark。可能需要创建一个自定义的书签类,实现IAOIBookmark接口,保存Extent信息,然后在定位时应用这个Extent。 首先,需要检查IAOIBookmark是否是正确的接口名称。在ArcGIS的文档中,常见的书签相关接口包括IBookmark、ISpatialBookmark、INamedBookmark等。可能用户提到的IAOIBookmark是自定义的或者特定版本的接口。假设这里是一个笔误,正确接口应为IBookmark,或者需要用户进一步澄清。 假设用户想要保存当前视图的Extent作为书签,并在定位时恢复该Extent。那么,可以创建一个类实现IBookmark接口,保存Extent,然后在Locate方法中设置pActiveView.Extent。 步骤如下: 1. 创建一个实现IBookmark接口的类,例如AOIBookmark。 2. 在Store方法中,保存当前ActiveView的Extent。 3. 在Locate方法中,将保存的Extent应用到ActiveView。 4. 修改btnLocate_Click事件处理函数,使用这个自定义的AOIBookmark来定位。 现在,编写代码示例: 首先,定义AOIBookmark类: public class AOIBookmark : IBookmark { private IEnvelope m_extent; public void Store(IActiveView activeView) { m_extent = activeView.Extent; } public void Locate(IActiveView activeView) { activeView.Extent = m_extent; activeView.Refresh(); } } 然后,在按钮点击事件中,使用这个书签: private void btnLocate_Click(object sender, EventArgs e) { IMapControl2 mapControl = axMapControl1.Object as IMapControl2; IActiveView activeView = mapControl.ActiveView; AOIBookmark bookmark = new AOIBookmark(); bookmark.Store(activeView); // 保存当前范围 // 假设之后需要恢复这个范围 bookmark.Locate(activeView); } 不过,用户可能想要替换原有的使用ISpatialBookmark的代码。例如,原来的代码可能是这样的: ISpatialBookmark spatialBookmark = new SpatialBookmarkClass(); spatialBookmark.Store(mapControl.Extent); spatialBookmark.Locate(mapControl); 现在,使用自定义的AOIBookmark和pActiveView.Extent来实现同样的功能。 需要确保在Store时保存Extent,在Locate时应用Extent。可能还需要处理书签的管理,比如保存多个书签,但用户的问题可能只需要基础的实现。 另外,用户提供的引用[1]中使用了pActiveView.PartialRefresh,这在定位后可能需要调用,以确保视图更新。 综上,修改后的btnLocate_Click函数可能如下: private void btnLocate_Click(object sender, EventArgs e) { // 获取当前ActiveView IActiveView pActiveView = axMapControl1.ActiveView; // 创建并存储书签 IBookmark bookmark = new AOIBookmarkClass(); // 假设AOIBookmark实现了IBookmark bookmark.Store(pActiveView); // 定位到书签 bookmark.Locate(pActiveView); pActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, pActiveView.Extent); } 但需要确认AOIBookmark是否正确实现IBookmark接口,或者是否可以直接使用现有的接口。 可能用户混淆了接口名称,因此需要验证。如果IAOIBookmark不存在,可能需要使用IBookmark,并确保Store和Locate方法正确处理Extent。 总结步骤: 1. 创建实现IBookmark接口的类,保存Extent。 2. 在按钮点击事件中实例化该类,调用Store保存当前视图范围。 3. 在需要定位时,调用Locate方法,设置Extent并刷新视图。</think>在Visual Studio 2019中使用`IActiveView.Extent`和自定义书签逻辑实现定位功能,可通过以下步骤完成: ### 一、实现原理 1. **替代方案**: 通过`IActiveView.Extent`直接操作地图范围,结合自定义书签存储结构(如字典或类属性),替代`ISpatialBookmark`的书签管理功能[^1][^2]。 2. **关键接口**: - `IActiveView`: 控制视图范围和刷新操作 - `IEnvelope`: 存储地理范围的坐标信息 --- ### 二、代码实现示例 #### 1. 定义书签管理类 ```csharp public class AOIBookmarkManager { private readonly Dictionary<string, IEnvelope> _bookmarks = new(); // 保存当前范围到书签 public void StoreBookmark(IActiveView activeView, string name) { IEnvelope envelope = activeView.Extent.Copy(); _bookmarks[name] = envelope; } // 定位到指定书签 public void LocateBookmark(IActiveView activeView, string name) { if (_bookmarks.TryGetValue(name, out var envelope)) { activeView.Extent = envelope; activeView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, activeView.Extent); } } } ``` #### 2. 修改btnLocate_Click事件 ```csharp private AOIBookmarkManager _bookmarkManager = new(); private void btnLocate_Click(object sender, EventArgs e) { // 获取当前视图 IMapControl2 mapControl = axMapControl1.Object as IMapControl2; IActiveView activeView = mapControl.ActiveView; // 示例:保存书签 _bookmarkManager.StoreBookmark(activeView, "默认位置"); // 示例:调用定位 _bookmarkManager.LocateBookmark(activeView, "默认位置"); } ``` --- ### 三、关键说明 1. **范围复制**: 使用`Copy()`方法创建`IEnvelope`的独立副本,避免直接引用导致的范围同步问题[^1]。 2. **视图刷新**: 通过`PartialRefresh`指定刷新地理要素层,确保地图显示更新[^1]。 3. **扩展性**: 可结合`ComboBox`控件实现书签列表选择功能,增强交互性。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值