线程安全的集合类

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

我会简单的介绍一些线程安全的集合类,还有它们的基本构成,大家请不要安心难度的问题,现在只是简单的了解一下.为什么要涉及线程安全的集合类呢?因为假如说我们要在多线程环境下使用,怎么办?这里提供了俩种方案.
1.最直接的办法,使用锁,手动保证~
多个线程去修改ArrayList 此时就可能有问题就可以给修改操作进行加锁~~
2.标准库还提供了一些线程安全的版本的集合类

多线程环境使用 ArrayList

在多线程环境中,使用 ArrayList 可能会引发线程安全问题。因为 ArrayList 并不是线程安全的容器,多个线程同时修改同一个 ArrayList 实例可能会导致数据不一致或者抛出异常。
如果非要使用的话,我提供了以下解决方案

  1. 自己使用同步机制 (synchronized 或者 ReentrantLock)
  2. Collections.synchronizedList(new ArrayList);

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

  1. 使用 CopyOnWriteArrayList
    CopyOnWrite容器即写时复制的容器。

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

优点:
在读多写少的场景下, 性能很高, 不需要加锁竞争.
缺点:

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

多线程环境使用队列

在多线程环境中,使用队列是非常常见的场景,但是需要注意队列的线程安全问题。以下是几种线程安全的队列:

ConcurrentLinkedQueue:这是一个线程安全的无界队列,内部使用单向链表实现,适合于高并发场景;
LinkedBlockingQueue:这是一个线程安全的有界队列,内部使用单向链表实现,适合于固定大小的任务队列;
ArrayBlockingQueue:这是一个线程安全的有界队列,内部使用数组实现,适合于固定大小的任务队列;
PriorityBlockingQueue:这是一个线程安全的优先级队列,内部使用堆实现,适合于按优先级排序的任务队列;
SynchronousQueue:这是一个线程安全的队列,没有任何内部容量,每个插入操作必须等待一个相应的删除操作,适合于生产者和消费者交替执行的场景。
以上队列都是线程安全的,能够在多线程环境中提供高效的并发操作。需要根据实际场景选择适合的队列类型,并根据具体需求设置容量、优先级等参数。

线程环境使用哈希表

ConcurrentHashMap:这是一个线程安全的哈希表,适合于高并发场景,内部采用分段锁机制,不同的段之间可以并发操作,能够提供更好的并发性能;

Hashtable:这是一个线程安全的哈希表,内部使用 synchronized 关键字来实现线程安全,但是并发性能不如 ConcurrentHashMap;

Collections.synchronizedMap():这是一个将非线程安全的哈希表转换为线程安全的哈希表的方法,内部使用 synchronized 关键字来实现线程安全,但是并发性能不如 ConcurrentHashMap。
以上哈希表都是线程安全的,能够在多线程环境中提供高效的并发操作。需要根据实际场景选择适合的哈希表类型,并根据具体需求设置容量、并发性能等参数。


当然我推荐使用ConcurrentHashMap,为什么呢?我们来看一下

Hashtable和 ConcurrentHashMap的对比.

1.锁的粒度不同

Hashtable
在这里插入图片描述
ConcurrentHashMap
在这里插入图片描述

2.锁的优化

ConcurrentHashMap,更充分的利用了CAS机制无锁编程.
有的操作,比如获取/更新元素个数,就可以直接使用CAS完成,不必加锁了
CAS也能保证线程安全,往往比锁更高效,但是这个东西咱们也不会特别经常使用.适用范围不像锁那么广泛

3.扩容方式不同

扩容触发条件:Hashtable 的扩容触发条件是当哈希表中元素个数大于等于阈值时,就需要进行扩容,阈值是容量 * 负载因子,负载因子默认为 0.75;ConcurrentHashMap 的扩容触发条件是当某个段的元素个数大于等于段容量的 75% 时,就需要对该段进行扩容。

扩容策略:HashTable的扩容需要重新申请内存空间,搬运元素(把元素从旧的哈希表上删掉,插入到新的哈希表上.)如果本身元素特别多,上亿个,搬运一次,成本就很高,就会导致这一次put操作就非常卡顿
ConcurrentHashMap的扩容策略就是,化整为零,并不会试图一次性就把所有的元素都搬运过去,而是每次搬运一部分.当put触发扩容,此时就会直接创建更大的内存空间,但不会直接把所有元素搬运过去,而是搬运一小部分.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
除了提供高性能的线程安全集合类,java的并发包还提供了以下功能: 1. 并发执行框架:java.util.concurrent包中的Executor框架提供了一种使用线程池的方式来执行并发任务。它将任务的提交与任务的执行解耦,可以通过线程池来管理和复用线程,并提供了任务执行的调度和控制的功能。 2. 并发工具类:并发包中还提供了一些工具类,如CountDownLatch、CyclicBarrier、Semaphore等,用于帮助实现更加复杂的并发控制。这些工具类可以用于同步多个线程的执行,控制线程的并发数量,并在一些条件满足后触发线程的执行等功能。 3. 原子操作类:并发包中提供了一系列原子操作类,如AtomicInteger、AtomicLong等,用于在多线程环境下对变量进行原子操作。这些类通过使用CAS(Compare and Swap)操作来保证变量的原子性,避免了使用synchronized关键字进行同步操作带来的性能开销。 4. 并发线程安全工具类:并发包中还提供了一些线程安全的辅助类,如CopyOnWriteArrayList、ConcurrentHashMap等,用于替代传统的非线程安全集合类。这些类通过使用一些特定的并发算法来保证多线程环境下的线程安全性,能够在并发读写的情况下提供较好的性能。 总之,java的并发包不仅提供了高性能的线程安全集合类,还提供了一些并发执行框架、并发工具类、原子操作类以及线程安全工具类,用于帮助开发者在多线程环境下更加方便、高效地编写并发代码。这些功能的引入使得开发者能够更好地处理并发程序的编写与调试,提高了程序的性能和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忘忧记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值