当前位置: 首页 > news >正文

Java集合再探

谈谈你对集合的理解?

集合首先分为两个集合和一个工具类,分别是Collection接口、Map接口以及Collections工具类

  1. 首先是Collection接口,也就是单例集合,它的子接口有List接口、Set接口、Queue接口

List接口首先是有序且允许重复,它的常见实现类

  • 有线程不安全的,例如:
    • ArrayList,底层是一个Object[]类型的elementData数组,适合查找、遍历,而插入\删除的效率比较低。它的无参构造方法首先是数组初始化为0,在第一次添加元素时,数组容量扩容为10;而有参构造方法,数组按指定容量初始化;当容量不足时,按数组现有容量的1.5倍扩容
    • LinkedList,底层是一个双向链表,在每个节点里存入了上个节点和下个节点的地址,适合插入、删除,而查找\遍历的效率比较低。它由于采用链表结构,每次添加元素都在创建新的Node节点并进行分配空间,所以不存在扩容。
  • 有线程安全的,例如:
    • Vector,底层也是一个Object[]类型的elementData数组,因为底层加了synchronized同步锁来实现线程安全,因此效率较低;它的扩容方式,无参构造方法,数组的初始化容量为10;而有参构造方法,数组按指定容量初始化;当容量不足时,按照原有的容量的2倍或者按照指定容量值(capacityIncrement)进行扩容。
    • Stack,底层是一个基于先进后出FILO实现的栈,底层加了synchronized同步锁来实现线程安全,它继承自Vector类。
    • CopyOnWriteArrayList,底层是一个Object[]类型的array数组,底层通过ReentrantLock锁来实现线程安全,由于底层是被final修饰的一把ReentrantLock锁,所以在不同的写操作(set、add、addIfAbsent、remove等方法)时,会保持线程之间的同步性(互斥),而读操作由于没加锁,所以允许读写操作同时进行;

CopyOnWrite:"写入"操作时,先进行数组复制,然后在新数组中进行写入操作,然后替换;

Set接口首先是无序且不允许重复,也就是值唯一,它的常见实现类

  • 有线程不安全的,例如:
    • HashSet,【特点:元素不重复且无序,允许null值】底层是HashMap。如果多个线程尝试修改HashSet,则最终结果是不确定的。
    • LinkedHashSet,【特点:元素有序,维护了元素的插入顺序】底层是LinkedHashMap。不支持按访问顺序对元素排序,只支持按插入顺序排序
    • TreeSet,【特点:可排序且去重,可以自定义排序规则】底层是TreeMap。底层用到的数据结果是红黑树。当我们构造TreeSet时;若使用不带参数的构造函数,则TreeSet的使用自然比较器;若用户需要使用自定义的比较器,则需要使用带比较器的参数。
  • 有线程安全的,例如:
    • CopyOnWriteArraySet,底层其实是CopyOnWriteArrayList,特点和它相同,读写分离,可能会产生脏读,在写上面加了ReentrantLock写锁,保持线程之间的同步性(互斥)

Queue接口,队列,先进先出FIFO

  • 有线程不安全的,例如:
    • LinkedList,基于双向链表实现的队列,底层是Node节点
    • PriorityQueue,基于堆实现的队列,底层是Object类型的数组
  • 有线程安全的,例如BlockingQueue阻塞队列,队列满,写入线程会阻塞,队列空,读取线程会阻塞。
    • ArrayBlockingQueue,有界队列,读写操作使用同一把ReentrantLock锁进行控制,所以读写操作不能并发。
    • LinkedBlockingQueue,无界队列,读takeLock写putLock使用各自不同的ReentrantLock锁,所以允许读写操作允许并发。
  1. Map接口,键值对集合,
  • 有线程不安全的,例如:
    • HashMap,【特点:无序,查找效率高,根据key查找value】底层是数组(哈希表)+链表(链地址法解决哈希冲突)+红黑树(自平衡二叉查找树,提高查找效率)

关键计算:计算key-value键值对在哈希表中的存储位置(桶),哈希运算,hash( )扰动函数【(h = key.hashCode()) ^ (h >>> 16)】计算新的哈希值,通过新哈希值,计算下标位置(桶位置)【(n - 1) & hash】

转换成红黑树的条件:链表的元素个数超过8,并且数组长度大于等于64

红黑树退化成链表条件:红黑树中的元素个数少于6

转换成红黑树的优点:

链表过长,会导致搜索效率降低,使用红黑树提高查找效率;

红黑树,是一颗自平衡的二叉查找树,树中所有节点均自动排序,并且自平衡,可以使用二分查找,提高查找效率。

影响性能的关键参数:

数组容量:默认为16,容量越大,内存占用越多,产生冲突的概率越小,必须为2的N次幂,每次按照2倍进行扩容,最大容量不超过2的30次幂;

加载因子:默认为0.75,加载因子越高,代表利用率越高,产生冲突的概率越高,加载因子越低,代表利用率越低,产生冲突的概率越低;

扩容条件:默认情况下,数组长度为16(自定义时,必须保证数组长度为2^n 次幂)达到扩容阈值threshold,按照2倍进行扩容,链表长度大于8,数组长度小于64,链表不会转换成红黑树,执行数组扩容

- <font style="background-color:#FBDE28;">LinkedHashMap</font>【HashMap的子类】键值对按照有序方式存储,在HashMap的基础上,多维护了一条双向链表,用于存储顺序
- <font style="background-color:#FBDE28;">TreeMap</font>:【自动按照key排序】底层使用红黑树存储
  • 有线程安全的,例如:
    • Hashtable【无序、key唯一、key和value不允许为null、线程安全】,哈希表 = 数组 + 单向链表,通过Synchronized实现线程安全。
    • ConcurrentHashMap【无序】,数组+链表+红黑树,通过Synchronized同步锁+CAS无锁化编程模型
  1. Collections工具类

ThreadLocal

ThreadLocal利用Thread中的ThreadLocalMap来进行数据存储。

内部有一个map对象,键为当前的线程对象,值为存储的数据value

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;/*** @Author Stringzhua* @Date 2024/11/1 10:19* description:*/
public class Demo01 {public static ThreadLocal<String> threadLocal = new ThreadLocal<>();public static ThreadLocal<Integer> threadLocalInt = new ThreadLocal<>();public static void main(String[] args) {show show = new show();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {try {threadLocal.set("妲己");threadLocalInt.set(10000);show.show();show.choose();} catch (Exception e) {e.printStackTrace();} finally {threadLocal.remove();threadLocalInt.remove();}}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {try {threadLocal.set("张飞");threadLocalInt.set(100);show.show();show.choose();} catch (Exception e) {e.printStackTrace();} finally {threadLocal.remove();threadLocalInt.remove();}}});t1.start();t2.start();}
}class show {public void show() {String role = Demo01.threadLocal.get();Integer score = Demo01.threadLocalInt.get();System.out.println(Thread.currentThread().getName() + "当前角色为" + role + "积分" + score);}public void choose() {String role = Demo01.threadLocal.get();Integer score = Demo01.threadLocalInt.get();System.out.println(Thread.currentThread().getName() + "选择的角色为" + role + "积分" + score);}
}

常用的方法

get()方法

set()方法

remove()方法

ThreadLocalMap底层:

在ThreadLocal里面的内部类里的ThreadLocalMap

初始化容量为16,是一个Entry[]类型的哈希表;

向下探查,开放地址法,而不是链地址法

当发生哈希冲突时,首先判断此处是否有值,若没有,直接存入。如果有值,则直接覆盖

ThreadLocal做key的原因?

首先是通过每个ThreadLocal对象的key,通过具体对的ThreadLocal对象的getMap()方法拿到ThreadLocalMap对象;再以当前的ThreadLocalMap对象为键,拿到Entry对象;然后从Entry对象中取到值。

如果是Thread对象做key的话,一个线程只能有一个Thread对象的key,那么就会产生混淆的问题。

ThreadLocalMap怎么查找数据?

以ThreadLocal对象作为key,通过访问Thread当前线程对象的内部ThreadLocalMap集合来获取到Value

相关文章:

  • 3452. 好数字之和
  • Java 模块化系统(JPMS)
  • 4.2.4 Thymeleaf内置对象
  • 无人机避障——深蓝学院浙大栅格地图以及ESDF地图内容
  • Mybatis的基本结构和说明
  • 支持PAM特权账号管理和人脸识别,JumpServer开源堡垒机v4.10 LTS版本发布
  • 选择排序 Python实现
  • 深度学习之-目标检测算法汇总(超全面)
  • Java 系统属性深度解析:从 API 校验到实战应用
  • 右键长按超过 200ms, 高亮选中的typora内容, win+a换颜色
  • 文件IO操作、目录操作
  • 软件开发的设计原则
  • 技术篇-2.2.JAVA应用场景及开发工具安装
  • 奥伦德OR-6N137-高速隔离运放光耦,替代6N137,自主晶圆,交期短
  • 什么是特征工程?
  • jmeter登录接口生成一批token并写入csv文件
  • “轩辕杯“云盾砺剑 CTF挑战赛web方向题解
  • 服务器数据恢复—V7000存储上raid5热备盘同步数据失败如何恢复数据?
  • fastadmin添加管理员账号只能查看一个表中指定条件的数据
  • String.join()-高效字符串拼接
  • 啥十小企业网站建设/百度识图搜索网页版
  • pxhere素材网站/电商网络销售是做什么
  • 微信小程序游戏制作/郑州seo推广
  • 成都培训学校网站建设/万网官网入口
  • 成都培训机构哪家好/seo优化厂商
  • 网站建设与管理题库/关键词林俊杰无损下载