【问题标题】:Make the ArrayList add thread-safe without using thread safe collections使 ArrayList 添加线程安全而不使用线程安全集合
【发布时间】:2018-11-18 15:41:08
【问题描述】:

我编写了一个执行 4 个线程的代码,每个线程会将 5000 个整数添加到一个列表中。 在执行结束时,我的列表中应该有 4 * 5000 个元素。 但我最终只有 1190(数字可能会改变)

这里是代码:

import java.util.ArrayList;
import java.util.List;

public class ConcurentList {
    public static void main(String[] args) throws InterruptedException {
        int range = 5000;
        int nbThreads = 4;

        List<Integer> integers = new ArrayList<>();
        ThreadSafeArrayList<Integer> integerThreadSafeArrayList = new ThreadSafeArrayList<>(integers);
        Thread[] arrayOfThread = new Thread[nbThreads];
        for (int i = 0; i < nbThreads; i++)
        {
            arrayOfThread[i] = new Thread(() -> {
                for (int j = 0; j < range; j++) {
                    integerThreadSafeArrayList.add(1);
                }
            });
            arrayOfThread[i].start();
            System.out.println("Le thread " + i + " ended.");
        }
        System.out.println("Size of the list " + integerThreadSafeArrayList.getSize());
    }
}

还有 ThreadSafeArrayList :

import java.util.List;

public class ThreadSafeArrayList<T> {
    private List<T> list;
    private final Object lock = new Object();

    public ThreadSafeArrayList(List<T> list) {
        this.list = list;
    }

    public boolean add(T element) {
        boolean add;
        synchronized (lock) {
            add = list.add(element);
        }
        return add;
    }

    public int getSize() {
        return list.size();
    }
}

我知道 arraylist 不是线程安全的,因此可以预测执行的行为,但是由于我使用了一个同步的私有最终锁,所以我希望获得正常的行为。

我错过了什么?

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    那是因为,当它被执行时,

    System.out.println("Size of the list " + integerThreadSafeArrayList.getSize());
    

    其他线程仍在运行并执行您要求它们执行的工作。

    要查看实际结果,请在最后一条语句之前添加这一行。

    TimeUnit.SECONDS.sleep(5);
    

    我现在可以看到的输出是:

    Le thread 0 ended.
    Le thread 1 ended.
    Le thread 2 ended.
    Le thread 3 ended.
    Size of the list 20000
    

    【讨论】:

    • 我太笨了... Ty
    【解决方案2】:

    有两个问题:

    1. 您需要加入已启动的线程,让它们在方法 main 结束之前完成工作。

      for (Thread thread : arrayOfThread) {
          thread.join();
      }
      
    2. getSize 方法不是线程安全的,因此需要使用同步:

      public int getSize() {
          synchronized (lock) {
              return list.size();
          }
      }
      

    【讨论】:

      【解决方案3】:

      等待结果

      for (int i = 0; i < nbThreads; i++) {
          arrayOfThread[i].join();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-10
        • 1970-01-01
        • 1970-01-01
        • 2011-03-30
        • 1970-01-01
        • 2019-12-01
        相关资源
        最近更新 更多