concurrentHashMap 并发场景下写入数据后丢失

发布于 2022-09-05 08:48:50 字数 3461 浏览 28 评论 0

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    public static void main(String[] args) throws Exception{
        while (true) {
            AtomicInteger atomicInteger = new AtomicInteger(0) ;
            ConcurrentHashMap<String, ConcurrentHashMap<String, String>> concurrentHashMapConcurrentHashMap = new ConcurrentHashMap<String, ConcurrentHashMap<String, String>>();
            Lock lock = new ReentrantLock() ;
            Condition condition = lock.newCondition() ;

            ExecutorService executor = Executors.newCachedThreadPool();
            for (int i = 0; i < 10; i++) {
                executor.execute(new PutThread(concurrentHashMapConcurrentHashMap ,atomicInteger , lock , condition));
            }

            lock.lock();
            while (atomicInteger.get() != 10){
                condition.await();
            }
            lock.unlock();

            System.out.println(concurrentHashMapConcurrentHashMap.get("topic").size());
            if (concurrentHashMapConcurrentHashMap.get("topic").size() != 500) {
                System.out.println("not ...");
            }

            concurrentHashMapConcurrentHashMap.clear();

            executor.shutdownNow() ;
        }
    }

    public static void put(String topic , String producerKey , String value , ConcurrentHashMap<String , ConcurrentHashMap<String , String>> concurrentHashMapConcurrentHashMap){
        synchronized (concurrentHashMapConcurrentHashMap) {
            if (concurrentHashMapConcurrentHashMap.containsKey(topic)) {
                concurrentHashMapConcurrentHashMap.get(topic).put(producerKey, value);
            } else {
                concurrentHashMapConcurrentHashMap.put(topic, new ConcurrentHashMap<String, String>());
                concurrentHashMapConcurrentHashMap.get(topic).put(producerKey, value);
            }
        }
    }
}

class PutThread implements Runnable{
    private volatile ConcurrentHashMap<String , ConcurrentHashMap<String , String>> concurrentHashMapConcurrentHashMap ;
    private volatile AtomicInteger atomicInteger ;
    private Lock lock ;
    private Condition condition ;

    public PutThread(ConcurrentHashMap<String, ConcurrentHashMap<String, String>> concurrentHashMapConcurrentHashMap, AtomicInteger atomicInteger, Lock lock, Condition condition) {
        this.concurrentHashMapConcurrentHashMap = concurrentHashMapConcurrentHashMap;
        this.atomicInteger = atomicInteger;
        this.lock = lock;
        this.condition = condition;
    }

    @Override
    public void run() {
        for(int i=0 ; i<50 ; i++){
            String id = Thread.currentThread().getName()+i ;
            Test.put("topic" , id , "xx" , concurrentHashMapConcurrentHashMap);
        }
        atomicInteger.addAndGet(1) ;

        lock.lock();
        condition.signal();
        lock.unlock();
    }
}

这段代码有什么问题吗?
为什么会有not ...打印呢?高并发场景下必显
java 版本是:java version "1.7.0_76"
clipboard.png

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

Oo萌小芽oO 2022-09-12 08:48:50

线程池复用导致key 重复了。。。

焚却相思 2022-09-12 08:48:50
executor.execute(new PutThread(concurrentHashMapConcurrentHashMap ,atomicInteger , lock , condition));

这个并不能保证执行用的是不同线程,比如线程A将第一个PutThread已经执行完毕,第二个PutThread还是被分配到线程A执行
那么:

String id = Thread.currentThread().getName()+i ;
Test.put("topic" , id , "xx" , concurrentHashMapConcurrentHashMap);

此时两次执行id均为A1-A50
也就是说,第二个PutThread把第一个PutThread覆盖掉了
Map.put(A1,xx)执行两次它的size是1,这个应该懂吧

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文