Java8下的ConcurrentHashMap新操作

更新值

       在Java7时,对ConcurrentHashMap进行线程安全的更新操作需要使用循环来处理(可以参见http://blog.youkuaiyun.com/zero__007/article/details/49833819),但是在Java8中提供了更方便的原子更新方法。
public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
     对于指定key做remappingFunction函数调用,remappingFunction函数返回值即为新的value,
     如果返回值为null,则从map中删除对应的key。compute返回key更新后的值(remappingFunction函数返回值)
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
     如果指定的key不存在,对该key做mappingFunction函数操作,mappingFunction函数返回值不为null,则将对应的k-v放到map中,否则不操作。
     如果key不存在computeIfAbsent返回值同mappingFunction,如果key存在返回key对应的value(此时mappingFunction不会调用)。
public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
     类似与computeIfAbsent,仅对已经存在的key才计算新value。同样,如果remappingFunction返回值为null,会删除对应的k-v。

compute示例:
public static void demo2() {
    final Map<String, Integer> count = new ConcurrentHashMap<>();
    final CountDownLatch endLatch = new CountDownLatch(2);

    count.put("b", 4);
    Runnable task = new Runnable() {
        @Override
        public void run() {
            Integer oldValue, newValue;
            for (int i = 0; i < 50; i++) {
                count.compute("a", new BiFunction<String, Integer, Integer>() {
                    @Override
                    public Integer apply(String k, Integer v) {
                        return v == null ? 1 : v + 1;
                    }
                });
            }
            endLatch.countDown();
        }
    };
    new Thread(task).start();
    new Thread(task).start();
    try {
        endLatch.await();
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println(count.compute("b", (k, v) -> {
        System.out.println(k + " --- " + v);
        return null;
    }));
    System.out.println(count.compute("a", (k, v) -> v == null ? 1 : v + 1));
    System.out.println(count);
}
运行结果:
b --- 4
null
101
{a=101}
还有一个新的操作merge:
public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)
    当key为尚未存在,直接插入对应value,remappingFunction不会被调用;否则,对oldValue与value做remappingFunction函数,结果作为新的newValue插入到map中。
    同样null结果会删除对应的k-v。
merge与compute不同之处在于,若key不存在,merge传入的函数不会调用,而compute传入的函数会有调用。

注意:使用merge或则compute方法时,所传入的函数不应该进行大量的工作。当该函数运行时,其它一些更新映射的操作可能会被阻塞。当然,该函数也不应该更新映射的其它部分。



批量数据操作

search 会对每个键和(或)值应用一个函数,直到该函数返回一个非null的结果,然后search会终止并返回该函数的结果。
reduce会通过提供的累计函数,将所有的键和(或)值组合起来。
forEach会对所有的键和(或)值应用一个函数。
具体的函数如下:
searchKeys/reduceKeys/forEachkey
searchValues/reduceValues/forEachValue
search/reduce/forEach
searchEntries/reduceEntries/forEachEntry
在使用这几个操作时需要指定一个并行阈值。如果希望操作在一个线程中,使用Long.MAX_VALUE作为阈值。

示例:
找到第一个出现次数超过1000的单词,需要搜索键和值:
String result = map.search(threshold, (k, v) -> v > 1000 ? k : null);
遍历所有键和值:
map.forEach(threshold, (k , v) -> sout(k + “ - ” + v));
或则可以接收一个转换/过滤函数:
map.forEach(threshold, 
            (k, v) -> v > 1000 ? k + “ - ” + v, null,//null不会被传递给消费者函数
            System.out::println);//消费者
### Java 8ConcurrentHashMap 的原理与实现机制 #### 数据结构的变化 在 Java 8 之前,`ConcurrentHashMap` 使用的是 `Segment` 数组来存储数据,每个 `Segment` 类似于一个小的哈希表。而在 Java 8 中,为了提高性能并减少锁的竞争,移除了 `Segment` 结构[^4]。的设计采用了一种混合的数据结构——数组加链表或者红黑树。 当某个桶(bucket)中的元素数量超过一定阈值(默认为 8),并且当前数组大小大于等于 64 时,该桶会从链表转换成红黑树以优化查找效率[^4]。这种变化使得即使在高负载情况下也能保持较好的性能。 #### 并发控制策略 Java 8 对并发控制进行了改进,摒弃了之前的分段锁方式,转而使用更加精细的锁定机制。具体来说,在插入节点或更已有节点时,只对涉及的具体链表头结点施加短暂的独占锁(`synchronized`);而对于读取操作,则完全不需要任何同步措施即可安全完成[^4]。 此外,对于一些特定的操作如计数器累加等原子性需求较高的场景,引入了 CAS (Compare And Swap) 技术配合 volatile 变量共同作用,从而进一步减少了因频繁获取释放锁带来的开销[^5]。 #### 扩容机制 扩容是另一个重要的方面。在旧版本里,整个 map 都会被重分配空间,并且所有 key-value pair 被复制到的位置上去。这种方式虽然简单粗暴却也带来了严重的阻塞问题。相比之下,Java 8 设计了一个渐进式的迁移过程:每次仅转移部分 bucket 至目标地址,允许其他线程继续正常工作而不受影响[^5]。这种方法不仅降低了单次调用所需时间长度,还提高了整体系统的响应速度和服务质量。 以下是简单的代码示例展示如何创建和使用 ConcurrentHashMap: ```java import java.util.concurrent.ConcurrentHashMap; public class Example { public static void main(String[] args){ ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); // 插入键值对 map.put("one", 1); map.putIfAbsent("two", 2); System.out.println(map.get("one")); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值