简体   繁体   English

ConcurrentHashMap.put() 总是线程安全的吗? 如果是这样,那么为什么它不能正常工作?

[英]is ConcurrentHashMap.put() always Thread-Safe? if so, then why it is not working correctly?

I wrote a class (userRepository) including a method named init().我写了一个 class (userRepository),包括一个名为 init() 的方法。 init method initializes ConcurrentHashMap, when I invoke this method in multiple threads (for example in three threads and in each thread for n times), I expect that the size of the map equals nx3. init 方法初始化 ConcurrentHashMap,当我在多个线程中调用此方法时(例如在三个线程中,每个线程中 n 次),我希望 map 的大小等于 nx3。 but it is not, on the other hand.但另一方面,事实并非如此。 when I use ReentrantLock or synchronized keyword on the signature of the method it works perfectly fine.当我在方法的签名上使用 ReentrantLock 或 synchronized 关键字时,它工作得很好。 I mean the size of the map is equal to nx3: please check the following example:我的意思是 map 的大小等于 nx3:请检查以下示例:

public class UserRepository implements CustomRepository<User, Integer> {
    private final Map<Integer, User> userMap = new ConcurrentHashMap<>();
    private int index = 0;

    public void init() {
        userMap.put(index, new User("User_" + index).setId(index));
        index++;
    }

    public List<User> findAll() {
        List<User> userList = new ArrayList<>();

        for (Integer id : userMap.keySet())
            userList.add(userMap.get(id));

        return userList;
    }
}
public class ChallengeApplication {
    static ExecutorService ex = Executors.newFixedThreadPool(2);

    public static void main(String[] args) {
        UserRepository userRepository = new UserRepository();

        int a = 5000000;
        long start = System.currentTimeMillis();
        ex.submit(() -> {
            for (int j = 0; j < a; j++)
                userRepository.init();
            long time = System.currentTimeMillis() - start;
            System.out.println(Thread.currentThread() + " finished in " + time);
        });

        ex.submit(() -> {
            for (int j = 0; j < a; j++)
                userRepository.init();
            long time = System.currentTimeMillis() - start;
            System.out.println(Thread.currentThread() + " finished in " + time);
        });

        for (int j = 0; j < a; j++)
            userRepository.init();
        long time = System.currentTimeMillis() - start;
        System.out.println(Thread.currentThread() + " finished in " + time);

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Size of map: " + userRepository.findAll().size());
    }
}

and this is the console output:这是控制台 output:

Thread[pool-1-thread-2,5,main] finished in 3832

Thread[main,5,main] finished in 3938

Thread[pool-1-thread-1,5,main] finished in 3996

Size of map: 14347920```

as you can see n=5000000 and there are 3 threads, so I expect that size of the pool equals 5000000*3= 15000000 but it is 13991739!如您所见,n=5000000 并且有 3 个线程,所以我希望池的大小等于 5000000*3= 15000000 但它是 13991739!

I would like to know what is the reason for this conflict??我想知道这个冲突的原因是什么??

please note that when I put synchronize keyword or using ReentrantLock it works correctly请注意,当我输入同步关键字或使用 ReentrantLock 时,它可以正常工作

The problem is not with the hash map itself but the index.问题不在于 hash map 本身,而在于索引。 You are using ++ which isn't an atomic command and thus isn't thread safe.您使用的 ++ 不是原子命令,因此不是线程安全的。 When you are using synchronized word on the function it syncs the index too and solves the problem.当您在 function 上使用同步字时,它也会同步索引并解决问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 ConcurrentHashMap put() 方法可以不是线程安全的吗? - Can ConcurrentHashMap put() method be not thread-safe? 在ConcurrentHashMap上进行此操作是否线程安全? - Is it Thread-safe on this operating on ConcurrentHashMap? ConcurrentHashMap.get()是否保证通过不同的线程看到以前的ConcurrentHashMap.put()? - Is ConcurrentHashMap.get() guaranteed to see a previous ConcurrentHashMap.put() by different thread? ConcurrentHashMap.put VS ConcurrentHashMap.replace - ConcurrentHashMap.put V.S. ConcurrentHashMap.replace 这个字典是否是线程安全的(ConcurrentHashMap + AtomicInteger)? - Is this dictionary function thread-safe (ConcurrentHashMap+AtomicInteger)? 如何测试ConcurrentHashMap是否真的是线程安全的? - How can I test that ConcurrentHashMap is truly thread-safe? ThreadLocal HashMap vs ConcurrentHashMap用于线程安全的未绑定缓存 - ThreadLocal HashMap vs ConcurrentHashMap for thread-safe unbound caches 如何执行线程安全获取然后使用ConcurrentHashMap删除? - How can I perform a thread-safe get then remove with ConcurrentHashMap? 在ConcurrentHashMap中放置线程安全的同时增加当前值? - Is incrementing of current value while putting thread-safe in ConcurrentHashMap? 为什么此代码不是“线程安全的”? - Why is this code not 'thread-safe'?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM