【多线程】线程安全的集合类

文章目录

    • 1. 多线程环境使用ArrayList
      • 1.1 自己使用同步机制
      • 1.2 Collections.synchronizedList(new ArrayList);
      • 1.3 使用 CopyOnWriteArrayList
    • 2. 多线程使用队列
    • 3. 多线程环境使用哈希表
      • 3.1 HashTable
      • 3.2 ConcurrentHashMap
      • 3.3 Hashtable和HashMap、ConcurrentHashMap 之间的区别?

学到现在,我们会发现原先学的大多集合类在多线程环境中使用并不是安全的,在并发编程中使用起来会有诸多问题,那么下面我们就要学习新的集合类和并发集合。
PS:Vector, Stack, HashTable, 是线程安全的,但不建议用,这是Java中旧的集合类,它们在性能、可读性、维护性等方面已经不如现在新的集合类和并发集合。

1. 多线程环境使用ArrayList

1.1 自己使用同步机制

自己使用同步机制,就是为ArrayList加锁,我们可以使用synchronized或ReentrantLock。

1.2 Collections.synchronizedList(new ArrayList);

synchronizedList 是标准库提供的一个基于 synchronized 进行线程同步的 List.
synchronizedList 的关键操作上都带有 synchronized,实现线程安全。

1.3 使用 CopyOnWriteArrayList

CopyOnWrite容器即写时复制的容器。
当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。
这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。
所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
优点
在读多写少的场景下, 性能很高, 不需要加锁竞争。
缺点

  1. 占用内存较多。
  2. 新写的数据不能被第一时间读取到。

2. 多线程使用队列

  1. ArrayBlockingQueue
    基于数组实现的阻塞队列
  2. LinkedBlockingQueue
    基于链表实现的阻塞队列
  3. PriorityBlockingQueue
    基于堆实现的带优先级的阻塞队列
  4. TransferQueue
    最多只包含一个元素的阻塞队列

3. 多线程环境使用哈希表

HashMap本身不是线程安全的。
并发编程中可以使用HashTable和ConcurrentHashMap。

3.1 HashTable

HashTable实现线程安全就是把关键的方法都加上锁,例如get(),put()方法,这个时候当多个线程访问HashTable就会发生锁冲突。
其实就相当于给HashTable对象进行了加锁,这个时候也会造成许多的弊端,例如:

  1. size属性也被加锁,那么多线程同时访问size的速度就会变慢,降低了效率。
  2. 当发生扩容操作时,就由该线程完成整个扩容过程. 这个过程会涉及到大量的元素拷贝, 效率会非常低。

3.2 ConcurrentHashMap

相比HashTable,ConcurrentHashMap就进行了优化,只对写操作进行加锁(锁的不是整个对象,而是‘桶锁’,以每个链表的头节点作为锁,那么,只有多线程同时访问一个桶时才会锁冲突),读并没有加锁(但是使用了volatile,保证内存的可见性)那么多线程读时,效率就会大大提升。
充分利用 CAS 特性:
比如 size 属性通过 CAS 来更新. 避免出现重量级锁的情况。
优化了扩容方式:
化整为零:
发现需要扩容的线程, 只需要创建一个新的数组, 同时只搬几个元素过去,
扩容期间, 新老数组同时存在,后续每个来操作 ConcurrentHashMap 的线程, 都会参与搬家的过程. 每个操作负责搬运一小部分元素, 搬完最后一个元素再把老数组删掉。这个期间, 插入只往新数组加,这个期间, 查找需要同时查新数组和老数组。

3.3 Hashtable和HashMap、ConcurrentHashMap 之间的区别?

HashMap: 线程不安全. key 允许为 null
Hashtable: 线程安全. 使用 synchronized 锁 Hashtable 对象, 效率较低. key 不允许为 null.
ConcurrentHashMap: 线程安全. 使用 synchronized 锁每个链表头结点, 锁冲突概率低, 充分利用CAS 机制. 优化了扩容方式. key 不允许为 null

你可能感兴趣的:(Java多线程编程,安全,网络,多线程,线程安全)