Java集合(13)——并发集合(1)——ArrayList、HashSet、HashMap线程不安全分析

目录

1.ArrayList线程不安全分析

1.1 故障现象

1.2 导致原因分析

1.3 解决方案

(1)使用Vector

(2)使用Collections.synchronizedList(List)

(3)使用CopyOnWriteArrayList

1.4 优化建议

2.HashSet线程不安全分析

2.1 故障分析

2.2 解决方案

(1)使用Collections.synchronizedSet()

(2)使用CopyOnWriteArraySet

3.HashMap线程不安全分析

3.1 故障现象

3.2 解决方案

(1)使用Collections.synchronizedMap()

(2)使用ConcurrentHashMap


1.ArrayList线程不安全分析

1.1 故障现象

示例代码:

package CollectionTest;

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

public class ArrayListDemo {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

当多个线程操纵同一个集合ArrayList的时候,抛出了java.util.ConcurrentModificationException

1.2 导致原因分析

  • ArrayList底层的所有方法,均未有任何机制来保证线程同步,所以当多个线程进行写操作如add、set的时候会出现并发修改的异常

1.3 解决方案

(1)使用Vector

package CollectionTest;

import java.util.List;
import java.util.UUID;
import java.util.Vector;

public class ArrayListDemo {

    public static void main(String[] args) {
        List<String> list = new Vector<>();

        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

(2)使用Collections.synchronizedList(List)

package CollectionTest;

import java.util.*;

public class ArrayListDemo {

    public static void main(String[] args) {
        List<String> list = Collections.synchronizedList(new ArrayList<>());

        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

(3)使用CopyOnWriteArrayList

package CollectionTest;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

public class ArrayListDemo {

    public static void main(String[] args) {
        List<String> list = new CopyOnWriteArrayList();

        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

1.4 优化建议

  • Vector的方法均使用synchronized修饰,单线程执行,在高并发下效率比较低,不建议使用
  • 关于Collections.SynchronizedList和CopyOnWrite的详细使用分析和建议见后续博客分析

2.HashSet线程不安全分析

2.1 故障分析

示例代码:

package CollectionTest;

import java.util.*;

public class HashSetDemo {

    public static void main(String[] args) {
        Set<String> set = new HashSet<>();

        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(set);
            },String.valueOf(i)).start();
        }
    }

}

2.2 解决方案

(1)使用Collections.synchronizedSet()

package CollectionTest;

import java.util.*;

public class HashSetDemo {

    public static void main(String[] args) {
        Set<String> set = Collections.synchronizedSet(new HashSet<>());

        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(set);
            },String.valueOf(i)).start();
        }
    }

}

(2)使用CopyOnWriteArraySet

package CollectionTest;

import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;

public class HashSetDemo {

    public static void main(String[] args) {
        Set<String> set = new CopyOnWriteArraySet<>();

        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(set);
            },String.valueOf(i)).start();
        }
    }

}

3.HashMap线程不安全分析

3.1 故障现象

package CollectionTest;

import java.util.*;

public class HashMapDemo {

    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();

        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,8));
                System.out.println(map);
            },String.valueOf(i)).start();
        }
    }

}

3.2 解决方案

(1)使用Collections.synchronizedMap()

package CollectionTest;

import java.util.*;

public class HashMapDemo {

    public static void main(String[] args) {
        Map<String,String> map = Collections.synchronizedMap(new HashMap<>());

        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,8));
                System.out.println(map);
            },String.valueOf(i)).start();
        }

    }

}

(2)使用ConcurrentHashMap

package CollectionTest;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class HashMapDemo {

    public static void main(String[] args) {
        Map<String,String> map = new ConcurrentHashMap<>();

        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,8));
                System.out.println(map);
            },String.valueOf(i)).start();
        }

    }
    
}

总结:

  • 可以发现ArrayList、HashSet、HashMap均是线程不安全的,因为在它们的实现中没有任何同步机制来保证线程同步
  • 它们均可以使用Collections.SynchronizedXXX方法来进行同步
  • 从JDK1.5开始,java.util.concurrent包下提供了一些并发集合供多线程场景下使用,后续博客会深入分析这些集合
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值