Java 集合是如何解决线程安全的?

 2022-09-20
原文地址:https://blog.csdn.net/qq_21083291/article/details/119760089

一、ArrayList线程安全问题

1、ArrayList例子

    List<String> strings = new ArrayList<>();
    //3个线程运行
    for (int i=0;i<30;i++)
    {
    new Thread(()->{
    strings.add(UUID.randomUUID().toString().substring(0,8));
    System.out.println(strings);
    },String.valueOf(i)).start();
    }
    
    故障问题,导致原因,如何修改,优化建议
     1、故障问题:java.util.ConcurrentModificationException
     2、导致原因:并发争抢修改导致 ,一个人在写,另一个在抢,会造成数据不一致。 list出现异常和线程不安全,出现null

2、解决方法

1、如何修改,使用Collections工具类

    //使用辅助工具类
    List<String> stringsColl = Collections.synchronizedList(new ArrayList<String>());
    for (int i=0;i<30;i++)
    {
    new Thread(()->{
    stringsColl.add(UUID.randomUUID().toString().substring(0,8));
    System.out.println(stringsColl);
    },String.valueOf(i)).start();
    }

2、写实复制,读写分离,优化,解决并发

内部用了lock锁加锁后复制新数组并将数组加一再写回去,set进集合里

    List<String> objects = new CopyOnWriteArrayList<>();
    for (int i=0;i<30;i++)
    {
    new Thread(()->{
    objects.add(UUID.randomUUID().toString().substring(0,8));
    System.out.println(objects);
    },String.valueOf(i)).start();
    }
    CopyOnWriteArrayList内部======
    public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
    		Object[] elements = getArray();
    		int len = elements.length;
    		Object[] newElements = Arrays.copyOf(elements, len + 1);
    		newElements[len] = e;
    		setArray(newElements);
    		return true;
    	} finally {
    		lock.unlock();
    	}
    }
    ======================

二、HashSet的解决线程安全

1、解决方法

1、使用Collections

    /**
    * 一解决
    */
    Set<String> strings = Collections.synchronizedSet(new HashSet<String>());
    for (int i=0;i<30;i++) {
    new Thread(()->{
    strings.add(UUID.randomUUID().toString().substring(0,8));
    System.out.println(strings);
    },String.valueOf(i)).start();
    }

2、使用CopyOnWriteArraySet

    /**
    * 二优化,hashSet一个参入得是key,value为写死的final Object
    */
    Set copyOnWriteArraySet = new CopyOnWriteArraySet();
    for (int i=0;i<30;i++) {
    	new Thread(()->{
    	copyOnWriteArraySet.add(UUID.randomUUID().toString().substring(0,8));
    	System.out.println(copyOnWriteArraySet);
    	},String.valueOf(i)).start();
    }

三、解决hashMap线程不安全

1、解决方法Collections

效率不高,锁太重

    //性能太低
    Map<String, Object> stringObjectMap = Collections.synchronizedMap(new HashMap<String, Object>());

2、使用ConcurrentHashMap

原理:jdk1.8中抛弃了segment的段锁,只保留segment的结构,而是直接用Node数组+链表+红黑树的数据结构来实现,并发控制使用Synchronized和CAS(自旋)来操作

    Map<String, Object> concurrentHashMap = new ConcurrentHashMap<>();

3、线程安全,有序,查询快的集合

    跳表遍历
    ConcurrentSkipListSet 基于ConcurrentSkipListMap