ArrayList的线程安全问题简述,以及如何优化

发布时间 2023-10-05 16:30:10作者: 斌哥的小弟
问题:

创建一个ArrayList,然后创建两个线程,每个线程for循环1000次向公共的List里面添加数据,在一个线程读取List当前的大小之后,另一个线程可能已经对List进行了修改。这样就可能导致数据的不一致性,例如一个线程读取到的List大小已经被另一个线程修改了,因此,在这个案例中,最终的列表大小可能不是期望值2000,而是一个小于或大于2000的随机值。这正是ArrayList线程不安全的一个典型表现。

 

解决方案:

1.使用Vector:Vector类与ArrayList类非常类似,但它的方法是同步的,可以确保在多线程环境中的安全访问和操作

Vector<Integer> list = new Vector<>();

        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                list.add(i);
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                list.add(i);
            }
        });

        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("List size: " + list.size());
    }
}

 

2.使用CopyOnWriteArrayList:CopyOnWriteArrayList是Java提供的一个线程安全的并发集合类,它通过每次添加、修改或删除元素时创建一个新的底层数组来实现线程安全,这种机制叫做写时复制。

  CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();

        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                list.add(i);
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                list.add(i);
            }
        });

        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("List size: " + list.size());
    }
}