多线程开辟中List的使用

打印 上一主题 下一主题

主题 1582|帖子 1582|积分 4746

由于ArrayList在多线程高并发环境下是不安全的,因此要慎用,那么此时如果涉及到集合操纵,应该怎么选:
方案一:Vector:

特点:通过给全部方法都用 synchronized 修饰从而保证线程安全,
缺点:CopyOnWriteArrayList


  • 高并发场景下性能较差(锁竞争严重)。
  • 即使单线程环境也会因同步开销影响性能。
总结:不发起使用。
方案二:Collections.synchronizedList

特点:低并发读写,简朴封装 ArrayList,全部方法加锁。
缺点:高并必环境下性能不如CopyOnWriteArrayList。
使用示例:
  1. List<String> syncList = Collections.synchronizedList(new ArrayList<>());
  2. // 复合操作仍需外部同步
  3. synchronized (syncList) {
  4.     if (!syncList.contains("value")) {
  5.         syncList.add("value");
  6.     }
  7. }
复制代码
方案三:CopyOnWriteArrayList

特点:
    1.读操纵:无锁,直接访问底层数组;
            2.写操纵:复制新数组,修改后替换旧数组(恰当 读多写少少 的场景)。
缺点:
           1.写操纵开销大(需复制数组)。
           2.数据一致性弱:读取的是某一时候的快照,大概读到旧数据。
使用示例:
  1. // 示例:事件监听器列表
  2. private final List<Listener> listeners = new CopyOnWriteArrayList<>();
复制代码
 拓展:
   CopyOnwriteArrayList通过JUC包下的lock来实现线程间的同步的, 可实现了读读操纵和读写操纵不互斥。
它是怎么实现读写不互斥的呢?
在面对写操纵的时候,CopyOnwriteArrayList会先复制原来的数组而且在新数组上举行修改,末了再将原数组覆盖。如果写操纵过程中发生了线程切换。而且切换到读线程,由于此时数组并未发生覆盖,读操纵读取的还是原数组。另外,数组界说private transient volatile Object[] array,其中采用volatile修饰,保证内存可见性,读取线程可以马上知道这个修改。也就是说当读写并发时读操纵是在旧数组中读到的旧值(一致性弱)。
  方案四:ConcurrentLinkedQueue

特点:
  1.高并发队列操纵(如任务分发),基于 CAS 无锁实现。
      2.线程安全:多线程并发添加无需额外同步。
      3. 无阻塞:操纵立刻返回,不会因锁竞争导致线程挂起。
      4. 无容量限制:队列会动态扩展。
缺点
        1.不支持随机访问(非 List 接口实现)。
        2.弱一致性:迭代器创建后,其他线程的修改大概不会立刻反映到遍历中。
        3.不支持 remove() 操纵:尝试通过迭代器删除元素会抛出 UnsupportedOperationException
使用示例:
  1. public class Main {
  2.     public static void main(String[] args) {
  3.         ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
  4.         
  5.         // 添加元素(推荐使用 offer)
  6.         queue.offer("A"); // 返回 true 表示成功
  7.         queue.add("B");   // 与 offer 等效
  8.       
  9.         // 读取并移除头部元素
  10.         String head1 = queue.poll(); // 返回 "A",队列变为 [B]
  11.         System.out.println("Polled: " + head1);
  12.         // 仅读取头部元素(不移除)
  13.         String head2 = queue.peek(); // 返回 "B",队列仍为 [B]
  14.         System.out.println("Peeked: " + head2);
  15.         // 队列为空时
  16.         queue.poll();               // 移除 "B",队列为空 []
  17.         String head3 = queue.poll(); // 返回 null
  18.         System.out.println("Polled empty: " + head3);
  19.     }
  20. }
复制代码
方案五:ConcurrentHashMap 

特点:可实现高性能随机访问,需要设置KEY.
方案对比:

开辟推荐

现代开辟中更推荐 CopyOnWriteArrayList?



  • 无锁读取:恰当多核 CPU 环境,避免线程阻塞。
  • 代码简洁:无需手动同步,淘汰错误。
  • 安全迭代:迭代器不会抛出 ConcurrentModificationException。
但需注意其 内存占用(写时复制会占用双倍空间)。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

用户云卷云舒

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表