程序员必知系列之三种构建线程安全的List集合的方法

245 阅读2分钟

这是我参与 8 月更文挑战的第 8 天,活动详情查看: 8月更文挑战

1.集合类线程不安全的场景

在多线程中,ArrayList是线程不安全的。 具体看下面的代码:

package JUC;

import javax.imageio.stream.ImageInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @Author MingJian_Zhu
 * @Date 2021/8/11 10:44
 */
public class ContainerNotSateDemo {
  
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
//        List<String> list = Collections.synchronizedList(new ArrayList<>());
//       List<String> arrayList = new CopyOnWriteArrayList<>();
        for(int i = 1;i<=30;i++){
        new Thread(()->{
            arrayList.add(UUID.randomUUID().toString().substring(0,8));
            System.out.println(arrayList);
        },String.valueOf(i)).start();

        }

    }
}

上面代码中运行结果出现了ConcurrentModificationException的异常报错,这是由于ArrayList是线程不安全引起的异常。 解决上面的方法:

2.使用线程安全的集合Vector

package JUC;

import javax.imageio.stream.ImageInputStream;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @Author MingJian_Zhu
 * @Date 2021/8/11 10:44
 */
public class ContainerNotSateDemo {
  
    public static void main(String[] args) {
        List arrayList = new Vector();
        for(int i = 1;i<=30;i++){
        new Thread(()->{
            arrayList.add(UUID.randomUUID().toString().substring(0,8));
            System.out.println(arrayList);
        },String.valueOf(i)).start();

        }

    }
}

3.使用Collection类构造线程安全的list

package JUC;

import javax.imageio.stream.ImageInputStream;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @Author MingJian_Zhu
 * @Date 2021/8/11 10:44
 */
public class ContainerNotSateDemo {
  
    public static void main(String[] args) {

        List<String> arrayList = Collections.synchronizedList(new ArrayList<>());
        for(int i = 1;i<=30;i++){
        new Thread(()->{
            arrayList.add(UUID.randomUUID().toString().substring(0,8));
            System.out.println(arrayList);
        },String.valueOf(i)).start();

        }

    }
}

4.使用JUC里面的类:CopyOnWriteArrayList

package JUC;

import javax.imageio.stream.ImageInputStream;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @Author MingJian_Zhu
 * @Date 2021/8/11 10:44
 */
public class ContainerNotSateDemo {
  
    public static void main(String[] args) {
       List<String> arrayList = new CopyOnWriteArrayList<>();
        for(int i = 1;i<=30;i++){
        new Thread(()->{
            arrayList.add(UUID.randomUUID().toString().substring(0,8));
            System.out.println(arrayList);
        },String.valueOf(i)).start();

        }

    }
}

5.总结

在多线程环境下,如何使用安全的集合List类是个重要的问题。在上述的解决方案中,个人推荐使用第二,三种的方法。针对第一种方法,因为Vector中存在着Syncronized的锁,所有在多线程程的使用环境下,会有极大的性能瓶颈问题;而第二和第三种采取的是不加锁的方法实现的。第三种称之为写时复制,该类每次添加元素的时候,都会拷贝上一次的内容出来,然后在其上次添加的元素上面添加元素,并且将原来指向旧的存储元素的空间的引用作废,将拷贝出来的存储空间指向原来的引用。