Java 使ArrayList添加线程安全,而不使用线程安全集合

Java 使ArrayList添加线程安全,而不使用线程安全集合,java,multithreading,Java,Multithreading,我编写了一个代码,执行4个线程,每个线程将向列表中添加5000个整数。 在执行结束时,我的列表中应该有4*5000个元素。 但最终我只有1190(数字可能会改变) 代码如下: import java.util.ArrayList; import java.util.List; public class ConcurentList { public static void main(String[] args) throws InterruptedException {

我编写了一个代码,执行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());
    }
}
import java.util.ArrayList;
导入java.util.List;
公共类并发列表{
公共静态void main(字符串[]args)引发InterruptedException{
整数范围=5000;
int=4;
列表整数=新的ArrayList();
ThreadSafeArrayList integerThreadSafeArrayList=新的ThreadSafeArrayList(整数);
线程[]arrayOfThread=新线程[nbThreads];
对于(int i=0;i{
对于(int j=0;j
和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();
    }
}
import java.util.List;
公共类ThreadSafeArrayList{
私人名单;
私有最终对象锁=新对象();
公共线程安全阵列列表(列表){
this.list=列表;
}
公共布尔加法(T元素){
布尔加法;
已同步(锁定){
添加=列表。添加(元素);
}
返回添加;
}
公共int getSize(){
返回list.size();
}
}
我知道arraylist不是线程安全的,因此它可以预测执行的行为,但由于我使用了一个同步的私有最终锁,所以我希望获得正常的行为


我遗漏了什么?

那是因为,当这个被执行时

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

那是因为,当它被执行时

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
有两个问题:

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

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

    public int getSize() {
        synchronized (lock) {
            return list.size();
        }
    }
    
  • 有两个问题:

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

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

    public int getSize() {
        synchronized (lock) {
            return list.size();
        }
    }
    
  • 等待结果

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

    for (int i = 0; i < nbThreads; i++) {
        arrayOfThread[i].join();
    }
    
    for(int i=0;i
    我太笨了。。。我太笨了。。。泰