簡體   English   中英

Java 意外的並發結果

[英]Java unexpected concurrent result

在測試並發時,我發現了一些意想不到的事情。

使用 concurrentHashMap 和 AtomicLong 控制並發。

public class HumanRepository {

    private final static Map<Long, Human> STORE = new ConcurrentHashMap<>();
    private AtomicLong sequence = new AtomicLong();

    public void save(Human human) {
        STORE.put(sequence.incrementAndGet(), human);
    }

    public int size() {
        return STORE.size();
    }


    public Long getSeq() {
        return sequence.get();
    }
}

我測試了多線程保存。

    @Test
    void name() throws NoSuchMethodException, InterruptedException {
        final int threads = 3_500;
        final ExecutorService es = Executors.newFixedThreadPool(threads);
        final CountDownLatch count = new CountDownLatch(threads);
        final HumanRepository repository = new HumanRepository();

        for (int i = 0; i < threads; i++) {
            try {
                es.execute(() -> repository.save(new Human("aa")));
            } finally {
                count.countDown();
            }
        }

        count.await();

        System.out.println("seq = " + repository.getSeq());
        System.out.println("size = " + repository.size());
    }

我同時用 3500 個線程測試了它。 我預期的結果是 seq 和 size 都是 3500。

但有時我得到 seq=3499,size=3500。 這很奇怪。 很奇怪,seq出來的不是3500,雖然size是3500,seq是3499也沒意義。

不知道為什么map里面的data number和seq不一樣,3500出不來。

** 如果你做Thread.sleep(400L); count.await(); ,奇怪的是,seq的值為3500

在此處輸入圖像描述

您實際上並不是在等待所有任務完成。 這意味着如果您獲得 3500/3500 output,那是偶然的。

具體來說,您在安排作業后減少主線程上的倒計時鎖存器,而不是在作業內部,一旦完成 這意味着您的 countdownlatch 基本上只是另一個不進行任何線程間通信的美化循環變量。 試試這樣的事情:

    for (int i = 0; i < threads; i++) {
        es.execute(() -> {
          repository.save(new Human("aa"));
          count.countDown();
        });
    }

您在執行 HumanRepository.save() 的線程外調用 count.countDown()。 因此,主線程可能未同步完成線程。

因此,您可能會在一個線程運行時看到 repository.getSeq() 的結果。 您可以嘗試使用以下代碼嗎?

        final int threads = 3_500;
        final ExecutorService es = Executors.newFixedThreadPool(threads);
        final CountDownLatch count = new CountDownLatch(threads);
        final HumanRepository repository = new HumanRepository();

        for (int i = 0; i < threads; i++) {
            try {
                es.execute(() -> {
                    repository.save(new Human("aa"));
                    count.countDown();
                });
            } finally {
                
            }
        }

        count.await();

        System.out.println("seq = " + repository.getSeq());
        System.out.println("size = " + repository.size());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM