java常见问题

java常见问题,第1张

java常见问题 java常见问题
    ConcurrentHashMap

ConcurrentHashMap的线程安全是保证单次 *** 作的原子性,仅仅使用ConcurrentHashMap不能保证线程安全,如果在多线程的情况下进行 *** 作依旧要对map进行加锁

public String right() throws InterruptedException {
    ConcurrentHashMap concurrentHashMap = getData(ITEM_COUNT - 100);
    log.info("init size:{}", concurrentHashMap.size());
    ForkJoinPool forkJoinPool = new ForkJoinPool(THREAD_COUNT);
    forkJoinPool.execute(() -> IntStream.rangeClosed(1, 10).parallel().forEach(i -> {
        //下面的这段复合逻辑需要锁一下这个ConcurrentHashMap
        synchronized (concurrentHashMap) {
            int gap = ITEM_COUNT - concurrentHashMap.size();
            log.info("gap size:{}", gap);
            concurrentHashMap.putAll(getData(gap));
        }
    }));
    forkJoinPool.shutdown();
    forkJoinPool.awaitTermination(1, TimeUnit.HOURS);
    log.info("finish size:{}", concurrentHashMap.size());
    return "OK";
}

提供了一些原子性的简单复合逻辑的 *** 作,比如computeIfAbsent

//利用computeIfAbsent()方法来实例化LongAdder,然后利用LongAdder来进行线程安全计数
ConcurrentHashMap freqs = new ConcurrentHashMap<>(ITEM_COUNT); 
freqs.computeIfAbsent(key, k -> new LongAdder()).increment();

额外的:computeIfAbsent和putIfAbsent的区别
除了最基础的参数不同以外,putIfAbsent是如果不存在参数一的key,将参数一和参数二作为键值对put到map当中,同时,原本存在该方法会返回key对应的value的值,原本不存在则会返回null,computeIfAbsent如果key不存在则将参数二的计算结果作为value值put到map当中

    ThreadLocal
    ThreadLocal在进行存储的时候是每个线程需要独立的进行保存信息,用作保存每个线程独享的对象,为每个线程都创建一个副本,这样每个线程都可以修改自己所拥有的副本, 而不会影响其他线程的副本,确保了线程安全,比如:当用户信息获取比较昂贵,如从数据库中获取,可以使用ThreadLocal进行存储用户信息,但是在利用ThreadLocal存储用户信息容易导致用户信息错乱,这点存在误区,我们在没有手动开启多线程的情况下,我们的web容器本身是并发的,会进行线程重用,当进行线程重用的时候,当前用户可能获取到的是上一个用户的信息,可以及时对ThreadLocal的信息进行清理,可以避免这类问题的出现。

    CopyOnWrite导致的性能问题
    在 Java 中,CopyonWriteArrayList 虽然是一个线程安全的 ArrayList,但因为其实现方式是,每次修改数据时都会复制一份数据出来,所以有明显的适用场景,即读多写少或者说希望无锁读的场景。当在有频繁的写 *** 作的时候CopyOnWrite的性能会十分糟糕,每次 add 时,都会用 Arrays.copyOf 创建一个新数组,频繁 add 时内存的申请释放消耗会很大。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5712599.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存