1. 系统功能树
- 用例图:关注有哪些角色,角色能够干什么。对需求分析的再次结构化
- 功能树:关注有哪些大的模块,功能模块能够实现什么能力。对用例图的重新聚合
- 部署图:关注部署元素(微服务,数据库),关注部署的关联元素
2. Java集合规约
1. Java集合框架图
集合是数据结构的载体,如下图:
2. 数据结构和时间复杂度
- 数据的组织方式:线性结构,树结构,图结构,哈希结构等。
- 数据处理方式:值逻辑意义上的数据组织方式及其对应的处理方式。数据的处理方式为
增、删、查、改,也就是我们经常所说的crud。以特定的算法实现对数据的增加、删除、修改、查找和遍历。 - 时间复杂度。
数据结构的优化与运算规模有关,也与调用频率有关。
时间复杂度从最好到最坏的排序如下:
常数级O(1) > 对数级O(logN) > 线性级O(N) > 线性对数级O(NlogN) > 平方级O(N2) > 指数级O(2N) > 阶乘级O(N!) - HashMap的基本概念
- table:存储所有节点数据的数组
- slot:哈希槽。即table[i]的这个位置
- bucket:哈希桶。table[i]上所有元素形成的表和树的集合
- HashMap的主干是一个Entry数组。它是HashMap的基本组成单元,每一个Entry都包含Node内部类
- HashMap的初始化
HashMap<Integer,String> map = new HashMap<>(13);
以上的代码初始化什么时候分配空间?分配多少存储空间呢?
在HashMap的源代码中,有一个核心方法,该方法用来处理给HaspMap分配空间,一般分配的空间都是2的指数。看下图:
在使用java8的lamda表达式把一个集合处理成map的时候,会发生
java.lang.IllegalStateExecption异常,我们查看xxx.stream().college(Collectors.toMap(xxx::getXxx, xxx::getXxx))中toMap的源码可以发现,所以按照java开发手册的规约,我们要加上参数类型为BinaryOperator,参数名为mergeFunction的方法。
以上虽然可以解决一个报错,但是也会报NPE的错误,通过查看源码可以知道在HashMap的merger方法里面有一个merge方法,会导致空指针异常
6. ArrayList的subList结果不可以强转为ArrayList
因为subList返回的结果是一个ArrayList的一个内部类(SubList),但是对于所有SubList的操作都会反映到ArrayList上面。所以如果我们直接强转的话,会报
ClassCastException异常。
- 在sublist场景中,高度注意对父集合元素的增加和删除,均会导致子列表的遍历、增加、删除产生
ConcurrentModificationException异常 - 每次sublist子列表的遍历、增加、删除都会调用checkForComodification()
3.并发处理
- 并行:同时处理多任务的能力
- 并发:指在某个时间段内,多任务交替处理的能力
1.线程安全
- 线程安全问题只在多线程环境下才出现,单线程串行执行不存在此问题
- 保证高并发场景下的线程安全,可以从以下方面来考虑
- 数据单线程内可见
- 只读对象
- 线程安全类
- 同步与锁机制
2. 什么是锁?
- 单线程时代没有锁的概念
- 多线程出现后,就有了资源竞争,就出现了锁机制
- Java中实现锁的方式:用并发包中的锁类,利用同步代码块
3.AQS透过现象看本质
本质:解决多线程访问共享资源并发问题的同步管理框架
- Abstract:包含tryAcquire、tryRelease等5个抽象方法,具体的实现由子类实现
- Queued队列:利用队列来管理竞争共享资源的多线程,这个队列是Node节点的引用虚拟实现
- Synchronizer同步器:是一个解决多线程同步问题的工具
4. Lock、AQS和AOS的关系
5. AQS同步队列
AQS通过CLH机制来管理Node节点的先来厚道,其中依Nodo对象的next、prev串起来的一个双向的同步队列
6. 线程与线程池的奥秘
- 线程可以拥有自己的操作栈,程序计数器,局部变量表等资源,它与同一进程内的其他线程共享该进程的所有资源
线程的状态信息:
7.线程池的作用
-
利用线程池管理并复用线程,控制最大并发数
-
增加对线程的管理、快速排查问题
-
实现任务线程队列缓存策略和拒绝机制
-
实现某些与时间相关的功能,如定时执行、周期执行等
-
隔离线程环境。比如在一台机器上面的两个服务,交易和搜索,就可以通过配置独立的线程池,将两个服务进行隔开,防止相互影响。