首页 > 其他分享 >ArrayList底层原理、线程安全及其相关集合(面试常问)

ArrayList底层原理、线程安全及其相关集合(面试常问)

时间:2023-08-07 22:12:29浏览次数:41  
标签:常问 LinkedList ArrayList 安全 Vector 线程 集合

一、ArrayList底层原理

1.特点及其原理:ArrayList底层基于数组实现,查找快,增删慢

8a3a04c1999d4f2b882b0fcb99a20923

2.ArrayList底层原理,初始化及调用add()方法添加元素:
默认初始化容量为10

e1728b4b542847019214512d858ef8d6

第一次创建集合并在添加第一个元素时在底层创建一个默认长度为10的数组: ​

调用构造函数初始化时默认创建的是空数组

4abaaba339ff4c1699f99903154a8f1d

c5d33ed6c5f24916ad782d58527964c3

只有在调用add方法添加第一个元素时才会在底层创建默认长度为10的数组

1bbaab44c34e4cf7a8f937a9eb48c270

41a00f2296f547759705f7ea966bd4df

48acf6a5397a4d088fa8cb48973ebb68

总结:第一次创建集合并添加第一个元素时在底层创建一个默认长度为10的数组;当元素插满,会进行扩容,每次扩容到之前的1.5倍(oldCapacity + (oldCapacity >> 1,二进制右移即除二,左移乘二),如果扩容1.5倍之后容量还不够,则将所需要的最小容量minCapacity赋给数组新的容量值newCapacity;扩容之后通过数组的拷贝(使用Arrays.copyOf)来确保元素的准确性。

二、ArrayList线程安全问题

由上图add()方法可知,在ArrayList中的add方法没有做相关线程安全的处理,故ArrayList本身是线程不安全的,与之相关的线程安全的方法有:

1.Vector类

Vector和ArrayList语法相同,都继承了同一个类实现了相同的接口

7d9120c169b349d69f50860ffe4fba26

d98b70993dd94034a374ff6a94700277

Vector中的add()方法添加了synchronized关键字,故Vector类是线程安全的

4811c07675df41bfb9db42a2d373781e

但是由于Vector是直接在方法上使用synchronized锁住整个方法,并发效率低,在高并发的情况下容 易造成线程阻塞等问题。

2.使用Collections工具类

使用集合的工具类Collections提供的synchronizedList方法将线程不安全的集合类变为安全的

//将线程不安全的集合对象作为参数传入synchronizedXxx()方法中
List synchronizedList = Collections.synchronizedList(arrayList);

a53c478aef1947c2854a249bb4e890f7

新new一个线程安全的SynchronizedRandomAccessList或SynchronizedList。当传入的 list 是ArrayList 时,返回 SynchronizedRandomAccessList 对象;传入 LinkedList 时,返回SynchronizedList 对象。(因为ArrayList实现了RandomAccess接口而 LinkedList 没有)

99aab8646eb249d2a9fca4a07ba0d8b3

而SynchronizedRandomAccessList又继承了SynchronizedList,在调用SynchronizedRandomAccessList时构造器会调用super(list)即SynchronizedList类

32af7d7afac34ef694d5b144884af0c0

可以看到SynchronizedList中的add、get、remove等方法内都加了mutex对象锁,从而实现线程安全。

与Vector比较,Vector直接锁住整个方法,而使用synchronizedList时锁住方法内部的部分代码,效率会高一点。

3.在大量并发情况下使用CopyOnWriteArrayList提高集合的效率和安全

d5873c6ae5d2476380884048ccaf91bf

使用Lock锁相较于Synchronized关键字更为灵活、效率更高;使用transient保证值被修改后,其它线程能够立马感知到最新值。且CopyOnWriteArrayList中只有写操作加了lock锁,而读操作(get方法)未加锁,从而提高读取效率(而synchronizedList和Vector中的get方法均加了synchronized关键字):

9ae34de6a5f948c3854a97c68649e5ac

从 add ()方法中可以看出,CopyOnWriteArrayList 通过volatile、加锁 、 以及数组拷贝来保证了集合的线程安全。

60f81ae2bebc4c5fb9f5d6fd3a4cc01d

总结:CopyOnWriteArrayList是一个读操作时无锁,写操作时使用volatile关键字、lock锁以及数组拷贝来保证线程安全的ArrayList。

三、ArrayList与相关集合的区别

1.ArrayList和LinkedList

  • ArrayList底层基于数组,LinkedList底层基于双链表

  • 广泛上来说:ArrayList适合查询,LinkedList适合插入,但是如果获取的是第一个元素,或最后一个元素,LinkedList查询也很快,因为LinkedList中有两个属性分别记录了当前链表中的头结点和尾结点。
    06e8462f4e8c4d3a9161ea4f250dd72a

  • ArrayList实现了RandomAccess接口,以便在随机访问列表或顺序访问列表时提供良好的性能;而LinkedList没有实现该接口。

    2.ArrayList和Vector

  • ArrayList同一时间允许多个线程进行访问,效率高、但是线程不安全,而Vector是线程安全的,但是效率低

  • ArrayList扩容是每次扩大到原来的1.5倍,Vector扩容是增加原来的两倍

  • ArrayList可使用集合工具类Collections的synchronizedList方法将线程不安全的ArrayList集合变为安全的,所以现在很少会使用到Vector

标签:常问,LinkedList,ArrayList,安全,Vector,线程,集合
From: https://www.cnblogs.com/dsshl/p/17612869.html

相关文章

  • Java HTTP多线程下载实现方法
    JavaHTTP多线程下载实现方法在如今互联网高速发展的时代,对于下载来说,速度是一个非常重要的因素。而多线程下载是一种提高下载速度的常见方法。本文将介绍如何使用Java编程实现HTTP多线程下载功能。JavaHTTP多线程下载实现方法一、背景知识在开始实现之前,我们需要了解一些基本......
  • 视频融合平台LiteCVR视频汇聚平台设备录像时间异常问题反馈解决案例
    LiteCVR视频融合平台是一个基于云边端协同架构的视频管理平台,支持海量视频的轻量化接入和汇聚管理。该平台提供了监控直播、云端录像、云存储、录像检索与回看、智能告警、平台级联、语音对讲、智能分析等丰富的视频能力,适用于工地、工厂、园区、楼宇、校园、仓储等各种场景。最近,......
  • 复习笔记|第十五章 Windows进程和线程管理《操作系统原理教程》
    参考教材:《操作系统原理教程(第4版)》刘美华翟岩龙著大纲问题回答(精简版)1.管理进程和线程的数据结构:执行体进程块EPROCESS、执行体线程块ETHREAD、内核进程块KPROCESS、内核线程块KTHREAD。structEPROCESS{P285KPROCESSPCB;内核进程块ObjectTable;进程的句......
  • 微服务项目线程池参数的合理设置
    一:线程池参数简介ThreadPoolExecutor类可设置的参数主要有:corePoolSize:核心线程1.核心线程会一直存活,及时没有任务需要执行2.当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理3.设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭queueCapacity:任......
  • Python创建线程
    importthreading,timedeffn1(x,y,z): whileTrue: print("I'mdoingsport.") print('args:%s%s%s'%(x,y,z)) time.sleep(1)deffn2(a,b,c): whileTrue: print("I'msinging.") time.sleep(1)if......
  • 面试官:线程是如何通讯的?
    线程通信是指多个线程之间通过某种机制进行协调和交互,例如,线程等待和通知机制就是线程通讯的主要手段之一。在Java中,线程等待和通知的实现手段有以下几种方式:Object类下的wait()、notify()和notifyAll()方法;Condition类下的await()、signal()和signalAll()方法;LockSupp......
  • 进程/线程模型
    进程/线程模型 进程模型 (一)多道程序设计 (Multiprogramming)允许多个程序同时进入内存并运行,其目的是为了提高系统效率。   并发环境与并发程序  并发环境:一段时间间隔内,单处理器上有两个或两个以上的程序同时处于开始运行但尚未结束的状态,并......
  • 线程
    程序、进程、线程程序:为完成某些特定任务,用某种语言编写的一组指令的集合,代码进程:程序的一次执行过程,正在运行的一个程序【这是一个动态过程,产生,存在,完成某些功能,消亡】线程:由进程创建的,是进程的一个实体,一个进程可以拥有多个线程【举个例子:一个正在读书并同时听音乐的人正在努力学......
  • 为什么不建议或不能用Executor去创建线程池?
    答:会存在内存溢出的风险。因为Executors中的核心方法,默认创建线程池的最大线程数是Integer.MAX_VALUE即int类型的最大值2^32-1,最大线程数允许这么多,几乎相当于不限制线程数,而这样的后果就是,如果瞬间请求量非常大,如果达到这个上限,没有任何服务器能够继续工作,肯定会抛出OOM异常。Ex......
  • linux修改线程数
    vim/etc/security/limits.d/90-nproc.conf查看核心线程数量ulimit-u......