Java知识
2023-06-05 11:01:03 0 举报
AI智能生成
登录查看完整内容
java学习知识,包含设计模式,数据库,redis等等相关内容
作者其他创作
大纲/内容
SqlSession级别的缓存
一级缓存
mapper级别的缓存
二级缓存
自定义注解
实现原理
MyBaties
ORM
验证项目
验证validate
执行编译
编译compile
测试
测试test
打包
包装package
检查
检查verify
安装
安装install
部署
部署deploy
构建声明周期
Maven
开闭原则
里氏代换原则
依赖倒转原则
接口隔离原则
一个软件实体应当尽可能少地与其他实体发生相互作用,通过中间类建立联系。
迪米特法则
合成复用原则
六大原则
工厂方法
抽象工厂
建造者
原型
普通创建
懒汉式(不安全)
懒汉式(安全)
饿汉式
内部类
双重锁验证
CAS
枚举
单例
创建型模式
适配器
桥接
组合
装饰
外观
享元
代理
结构型模式
责任链
命令
迭代器
中介者
备忘录
观察者
状态
策略
模板方法
访问者
行为模式
23种设计模式
设计模式
分支主题
JVM结构概览图
七种常见的垃圾回收器以及回收算法
采用了GC的复制算法,速度快,因为新生代一般是新对象,都是瞬态的用了可能很快被释放的对象
复制算法
新生代JDK1.8默认 Parallel Scavenge
GC后会执行压缩,整理到一个连续的空间,这样就维护着下一次分配对象的指针,下一次对象分配就可以采用碰撞指针技术,将新对象分配在第一个空闲的区域
标记/整理算法
老年代JDK1.8默认 Parallel Old
垃圾回收
-Xss
-Xms
-Xmx
Jvm调优
加载
验证
准备
解析
链接
初始化
使用
卸载
类加载过程
自定义加载器
应用加载器
扩展加载器
根加载器
加载器双亲委派机制
双亲委派机制
图示
类加载
内存溢出(Out Of Memory)申请内存时,JVM没有可以申请的内存了
内存泄露 (Memory Leak)一直不释放自己持有的内存,长时间会引起内存溢出
内存泄露&内存溢出
子主题 5
JVM
长度16 加载因子0.75f
扩容机制
数组+链表
jdk1.7
数组+链表+红黑树
jdk1.8
不是大于8就转红黑树,不是小于6就转链表
实现
HashMap
Map
默认长度10,1.5倍扩容
ArrayList
LinkedList(不继承List)
List序列
1. ArrayList和LinkedList的差别主要来自于Array和LinkedList数据结构的不同。 ArrayList是基于数组实现的,LinkedList是基于双链表实现的。另外LinkedList类不 仅是List接口的实现类,可以根据索引来随机访问集合中的元素,除此之外, LinkedList还实现了Deque接口,Deque接口是Queue接口的子接口,它代表一个双向 队列,因此LinkedList可以作为双向队列 ,栈(可以参见Deque提供的接口方法)和 List集合使用,功能强大。
3. 相对于ArrayList,LinkedList的随机访问集合元素时性能较差,因为需要在双向列表中 找到要index的位置,再返回;但在插入,删除操作是更快的。因为LinkedList不像 ArrayList一样,不需要改变数组的大小,也不需要在数组装满的时候要将所有的数据重 新装入一个新的数组,这是ArrayList最坏的一种情况,时间复杂度是O(n),而 LinkedList中插入或删除的时间复杂度仅为O(1)。ArrayList在插入数据时还需要更新索 引(除了插入数组的尾部)。
4. LinkedList需要更多的内存,因为ArrayList的每个索引的位置是实际的数据,而 LinkedList中的每个节点中存储的是实际的数据和前后节点的位置。
区别
HashSet
Set集
Queue队列
Collection
数据结构
byte(1字节 8位,-128~127)
short(2字节 16位)
int(4字节 32位)
long(8字节 64位)
整型
float(4字节 32位)
double(8字节 64位)
浮点型
char(2字节 16位)
字符型
boolean (1字节)
布尔型
8种常见数据类型
基本知识
集成Thread类,实现run()方法
实现Runnable接口,实现run()方法
实现Calable接口,实现call()方法(有返回值)
创建方法
新建(new)
可运行(Runnable)
运行中(Running)
等待阻塞
同步阻塞
其他阻塞
阻塞(Blocking)
状态图
死亡(Dead)
线程状态
Running
ShutDown
Stop
Tidying
Terminated
线程池状态
线程池流程
自定义线程池,new ThreadPoolExecutor
缓存线程池,Executors.newCachedThreadPool()
单线程线程池,Executors.newSingleThreadExecutor()
固定线程数线程池,Executors.newFixedThreadPool(5)
定时定长线程池,Executors.newScheduledThreadPool(5)
线程池
容易因请求队列超长OOM
容易因线程数量过多OOM
执行顺序参考:https://www.imooc.com/article/5887
自旋锁(spinlock)
互斥锁(mutex)
读写锁(RWLock)
悲观锁和乐观锁这个概念主要用于数据库高并发的场景
悲观锁
乐观锁
悲观锁和乐观锁
公平锁和非公平锁主要在于线程的资源公平性
公平锁
非公平锁
公平锁和非公平锁
其他分类方式
锁
线程内存
MESI机制:
Volatile关键字是如果做到值改变后通知其他线程
共享变量
ThreadLocal
多线程
FileNotFoundException
IOException
ClassNotFoundException
NullPointerException
ArrayIndexOutOfBoundsException
UnKnownTypeException
IllegalArgumentException
RuntimeException
Exception
StackOverFlowError
OutOfMemoryError
VirtuMachineError
AWTError
Error
Throwable
异常
Java
DI(依赖注入)
IOC(控制反转)
AOP(切面拦截)
三大特性
Spring 解决循环依赖的核心就是提前暴露对象,而提前暴露的对象就是放置于第二级缓存中。缓存的底层都是Map,至于它们属于第几层是由Spring获取数据顺序以及其作用来表现的。
思想
一级缓存,存放完整的 Bean。
singletonObjects
二级缓存,存放提前暴露的Bean,Bean 是不完整的,未完成属性注入和执行 初始化(init) 方法。
earlySingletonObjects
三级缓存,存放的是 Bean 工厂,主要是生产 Bean,存放到二级缓存中。
singletonFactories
三级缓存
1 A创建过程中需要B,于是A将自己放到三级缓存里面,去实例化B
2 B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A然后把三级缓存里面的这个A放到二级缓存里面,并删除三级缓存里面的A
3 B顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态)然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到B,然后完成创建,并将A自己放到一级缓存里面。
A/B对象的迁移
流程
实现方式
实例化:堆内存中申请一块内存空间
初始化:完成属性的各种赋值
区分
循环依赖
@Transactional
事务注解
事务隔离级别
1、singleton:单例,默认作用域。
2、prototype:原型,每次创建一个新对象。
3、request:请求,每次Http请求创建一个新对象,适用于WebApplicationContext环境下。
4、session:会话,同一个会话共享一个实例,不同会话使用不用的实例。
5、global-session:全局会话,所有会话共享一个实例
Spring Bean作用域
https://www.cnblogs.com/myseries/p/11729800.html
Spring Bean是线程安全的么
常见问题
Spring
@SpringBootApplication
@EnableAutoConfiguration
@SpringBootConfiguration
@ComponentScan
@Configuration
核心注解有哪些
@RestController
@GetMapping
@PostMapping
@RequestMapping
常用注解
声明方法
@Documented
@Retention
@Target
元注解
AOP
注解
https://blog.csdn.net/weixin_44947701/article/details/124055713
启动流程
参考1https://blog.csdn.net/LNView/article/details/93338432
怎么扫描的Bean
SpringBoot
Nacos(服务注册配置中心)
Gateway(网关)
Sentinel(限流)
OpenFeign(接口调用)
Seata(分布式事务解决方案)
SkyWalking(链路追踪)
组件
SpringCloud Alibaba
Java框架
原子性(Atimicity)
一致性(Consistency)
隔离性(Isolation)
持久性(Durability)
事务性
脏读
不可重复读(侧重修改)
幻读(侧重新增删除)
不可重复读&幻读
事务并发的问题
读未提交(read-uncommitted)
读已提交(read-committed)
可重复读(repeatabel-read Innodb默认隔离级别)
串行化(serializable)
事务
Innodb
MyISAM
引擎
聚集索引
非聚集索引
物理储存维度
B+数索引
哈希索引
全文索引
R-Tree索引
数据结构维度
主键索引
唯一索引
普通索引
联合索引
空间索引
逻辑维度
索引
1、id相同:执行顺序由上至下 。
2、id不同:如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行 。
3、id相同又不同(两种情况同时存在):id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行
select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
id
SIMPLE
PRIMARY
UNION
SUBQUERY
类型
简单表,不使用表连接或子查询
主查询,即外层的查询
UNION中的第二个或者后面的查询语句
子查询中的第一个
说明
查询的类型,主要是用于区分普通查询、联合查询、子查询等复杂的查询
select_type
输出结果集的表(表别名)
table
ALL
全表扫描
一般是没有where条件或者where条件没有使用索引的查询语句
差
index
索引全扫描
索引全扫描,MySQL遍历整个索引来查询匹配行,并不会扫描表。一般是查询的字段都有索引的查询语句
range
索引范围扫描
索引范围扫描,常用于<、<=、>、>=、between等操作
ref
非唯一索引扫描
使用非唯一索引或唯一索引的前缀扫描,返回匹配某个单独值的记录行
eq_ref
唯一索引扫描
类似ref,区别在于使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配
单表最多有一个匹配行
单表中最多有一条匹配行,查询起来非常迅速,所以这个匹配行的其他列的值可以被优化器在当前查询中当作常量来处理
NULL
不用扫描表或索引
MySQL不用访问表或者索引,直接就能够得到结果
好
表示MySQL在表中找到所需行的方式,或者叫访问类型。常见访问类型如下,从上到下,性能由差到最好:
type
表示查询可能使用的索引
possible_keys
实际使用的索引
key
使用索引字段的长度
key_len
使用哪个列或常数与key一起从表中选择行。
扫描行的数量
rows
Distinct
优化distinct操作,在找到第一个匹配的元素后即停止查找
子主题 1
Not exists
使用not exists来优化查询
子主题 2
执行情况的说明和描述,包含不适合在其他列中显示但是对执行计划非常重要的额外信息
Extra
执行计划
参考链接:https://blog.csdn.net/huaishu/article/details/89924250
多版本并发控制(Innodb引擎下)
MVCC只在 READ COMMITTED 和 REPEATABLE READ 两个隔离级别下工作
InnoDB在每行数据都增加三个隐藏字段,一个唯一行号,一个记录创建的版本号,一个记录回滚的版本号。
在多版本并发控制中,为了保证数据操作在多线程过程中,保证事务隔离的机制,降低锁竞争的压力,保证较高的并发量。在每开启一个事务时,会生成一个事务的版本号,被操作的数据会生成一条新的数据行(临时),但是在提交前对其他事务是不可见的,对于数据的更新(包括增删改)操作成功,会将这个版本号更新到数据的行中,事务提交成功,将新的版本号更新到此数据行中,这样保证了每个事务操作的数据,都是互不影响的,也不存在锁的问题。
undo-log
MVVC的实现机制
MVVC
用双节点数据库,搭建单向或者双向的半同步复制。通常会和proxy、keepalived等第三方软件同时使用,即可以用来监控数据库的健康,又可以执行一系列管理命令。如果主库发生故障,切换到备库后仍然可以继续使用数据库。
架构、部署比较简单,主机宕机直接切换即可
优点
完全依赖于半同步复制,半同步复制退化为异步复制,无法保证数据一致性;另外,还需要额外考虑haproxy、keepalived的高可用机制
缺点
优缺点
主从或主主半同步复制
半同步复制机制是可靠的,可以保证数据一致性的。但是如果网络发生波动,半同步复制发生超时会切换为异步复制,异复制是无法保证数据的一致性的。因此,可以在半同复制的基础上优化一下,尽可能保证半同复制。如双通道复制方案
这种方案架构、部署也比较简单,主机宕机也是直接切换即可。比方案1的半同步复制,更能保证数据的一致性。
需要修改内核源码或者使用mysql通信协议,没有从根本上解决数据一致性问题
半同步复制优化
保证高可用,可以把主从双节点数据库扩展为数据库集群。Zookeeper可以作为集群管理,它使用分布式算法保证集群数据的一致性,可以较好的避免网络分区现象的产生。
保证了整个系统的高可用性,扩展性也较好,可以扩展为大规模集群
数据一致性仍然依赖于原生的mysql半同步复制;引入Zookeeper使系统逻辑更复杂
高可用架构优化
共享存储实现了数据库服务器和存储设备的解耦,不同数据库之间的数据同步不再依赖于MySQL的原生复制功能,而是通过磁盘数据同步的手段,来保证数据的一致性。
DRBD是一个用软件实现的、无共享的、服务器之间镜像块设备内容的存储复制解决方案。主要用于对服务器之间的磁盘、分区、逻辑卷等进行数据镜像,当用户将数据写入本地磁盘时,还会将数据发送到网络中另一台主机的磁盘上,这样的本地主机(主节点)与远程主机(备节点)的数据就可以保证实时同步。当本地主机出现问题,远程主机上还保留着一份相同的数据,即可以继续使用,保证了数据的安全。
DRBD磁盘复制
部署简单,价格合适,保证数据的强一致性
对IO性能影响较大,从库不提供读操作
共享存储
分布式协议可以很好解决数据一致性问题。常见的部署方案就是MySQL cluster,它是官方集群的部署方案,通过使用NDB存储引擎实时备份冗余数据,实现数据库的高可用性和数据一致性。
不依赖于第三方软件,可以实现数据的强一致性;
配置较复杂;需要使用NDB储存引擎;至少三节点;
分布式协议
高可用方案
MySQL
1、 加索引2、避免返回不必要的数据3、适当分批量进行4、优化sql结构5、分库分表6、读写分离
SQL优化
表中的每个字段都不能再拆分了
第一范式:
满足第一范式且非主键字段都依赖于主键字段
第二范式:
满足第二范式并且表中的非主键字段必须不传递依赖于主键字段,每一列 数据和主键直接相关。
第三范式:
三大范式
数据库
缓存、计数器、分布式锁等。
场景:
int
数字
长度<39:enbstr
长度>39:raw
字符串
数据编码
String: 字符串最大长度512M
链表、队列、微博关注人时间轴列表等。
列表的元素个数<512 & 列表的每个元素值都<64字节(默认)使用ziplist
不满足上述linkedlist
List: 列表最多存储元素2^32-1
用户信息、Hash 表等。
哈希类型元素个数<512个 &所有值都<64字节(默认)ziplist
不满足上述hashtable
Hash: 散列
去重、赞、踩、共同好友等。
元素都是整数&元素个数<512个intset
Set: 集合
访问量排行榜、点击量排行榜等。
有序集合元素个数<128个&每个元素的值<64ziplist
不满足上述skiplist
ZSet: 有序集合
数据结构&应用场景
底层实现
RDB
AOF
持久化
分布式锁
指单个key在缓存中查不到,去数据库查‼️‼️这里指的是单个key发生高并发
通过synchronized+双重检查机制:某个key只让一个线程查询,阻塞其它线程
设置value永不过期
使用互斥锁(mutex key)
解决方案
击穿
一般是出现这种情况是因为恶意频繁查询才会对系统造成很大的问题: key缓存并且数据库不存在,所以每次查询都会查询数据库从而导致数据库崩溃。
布隆过滤器
缓存及穿透的key
穿透
雪崩指的是多个key查询并且出现高并发,缓存中失效或者查不到,然后都去db查询,从而导致db压力突然飙升,从而崩溃。
描述
key同时失效
redis本身崩溃
原因
雪崩
击穿&穿透&雪崩
基础知识
哨兵
集群
1、设置主节点的地址和端口2、建立套接字连接3、发送PING命令4、权限验证5、同步6、命令传播
主从复制原理
纯内存操作
单线程操作,无锁竞争
C语言实现,更接近底层
多路I/O复用模型,非阻塞IO
数据结构简单,底层又做了优化
源码精湛,简短
为什么快
定时过期
惰性过期
定期过期
过期策略
当内存不足以容纳新写入数据时,从设置了过期时间的key中使用LRU(最近最少使用)算法进行淘汰;
volatile-lru
当内存不足以容纳新写入数据时,从所有key中使用LRU(最近最少使用)算法进行淘汰
allkeys_lru
4.0版本新增,当内存不足以容纳新写入数据时,在过期的key中,使用LFU算法进行删除key。
volatile-lfu
4.0版本新增,当内存不足以容纳新写入数据时,从所有key中使用LFU算法进行淘汰
allkeys-lfu
当内存不足以容纳新写入数据时,从设置了过期时间的key中,随机淘汰数据
volatile-random
当内存不足以容纳新写入数据时,从所有key中随机淘汰数据
allkeys_random
当内存不足以容纳新写入数据时,在设置了过期时间的key中,根据过期时间进行淘汰,越早过期的优先被淘汰
volatile-ttl
默认策略,当内存不足以容纳新写入数据时,新写入操作会报错
noeviction
内存淘汰策略
过期策略和内存淘汰策略
Redis
脑裂
解耦
削峰
异步处理
消息通讯
远程调用
功能
示意图
当 consumer 使用集群消费时,每条消息只会被 consumer 集群内的任意一个 consumer 实例消费一次。举个例子,当一个 consumer 集群内有 3 个consumer 实例(假设为consumer 1、consumer 2、consumer 3)时,一条消息投递过来,只会被consumer 1、consumer 2、consumer 3中的一个消费。同时记住一点,使用集群消费的时候,consumer 的消费进度是存储在 broker 上,consumer 自身是不存储消费进度的。消息进度存储在 broker 上的好处在于,当你 consumer 集群是扩大或者缩小时,由于消费进度统一在broker上,消息重复的概率会被大大降低了。注意:在集群消费模式下,并不能保证每一次消息失败重投都投递到同一个 consumer 实例。
集群消费
当 consumer 使用广播消费时,每条消息都会被 consumer 集群内所有的 consumer 实例消费一次,也就是说每条消息至少被每一个 consumer 实例消费一次。举个例子,当一个 consumer 集群内有 3 个 consumer 实例(假设为 consumer 1、consumer 2、consumer 3)时,一条消息投递过来,会被 consumer 1、consumer 2、consumer 3都消费一次。与集群消费不同的是,consumer 的消费进度是存储在各个 consumer 实例上,这就容易造成消息重复。还有很重要的一点,对于广播消费来说,是不会进行消费失败重投的,所以在 consumer 端消费逻辑处理时,需要额外关注消费失败的情况。虽然广播消费能保证集群内每个 consumer 实例都能消费消息,但是消费进度的维护、不具备消息重投的机制大大影响了实际的使用。因此,在实际使用中,更推荐使用集群消费,因为集群消费不仅拥有消费进度存储的可靠性,还具有消息重投的机制。而且,我们通过集群消费也可以达到广播消费的效果。
广播消费
消费模式
处理过程图
同步发送-默认(丢失概率最低)
异步发送:
Oneway发送:
1、提供SYNC的发送消息方式,等待broker处理结果
2、发送消息如果失败或者超时,则重新发送
3、broker提供多master模式,即使某台broker宕机了,保证消息可以投递到另外一台正常的broker上
Producer发送消息阶段
producer消息发送方式虽然有3种,但为了减小丢失消息的可能性尽量采用同步的发送方式,同步等待发送结果,利用同步发送+重试机制+多个master节点,尽可能减小消息丢失的可能性
提供同步刷盘的策略
提供主从模式,同时主从支持同步双写
Broker处理消息阶段
在broker端,消息丢失的可能性主要在于刷盘策略和同步机制。RocketMQ默认broker的刷盘策略为异步刷盘,如果有主从,同步策略也默认的是异步同步,这样子可以提高broker处理消息的效率,但是会有丢失的可能性。因此可以通过同步刷盘策略+同步slave策略+主从的方式解决丢失消息的可能
先提交后消费
先消费,消费成功后再提交(RocketMQ默认方式)
consumer默认提供的是At least Once机制
consumer端要保证消费消息的可靠性,主要通过At least Once+消费重试机制保证。
消费消息重试机制
Consumer消费消息阶段
三个阶段
如何保证消息不会丢失
消费端处理消息的业务逻辑保持幂等性
保证每条消息都有唯一编号且保证消息处理成功与去重表的日志同时出现
如何保证消息不被重复消费
RocketMQ
ElasticSearch
Kafka
k8s
rancher
中间件
缺点:递归效率低性能低;释放空间不连续容易导致内存碎片;会停止整个程序运行;
标记/清除算法
把内存分成两块区域:空闲区域和活动区域,第一还是标记(标记谁是可达的对象),标记之后把可达的对象复制到空闲区,将空闲区变成活动区,同时把以前活动区对象1,4清除掉,变成空闲区。
缺点:速度快但耗费空间,假定活动区域全部是活动对象,这个时候进行交换的时候就相当于多占用了一倍空间,但是没啥用。
标记整理算法
垃圾回收GC算法引用计数法&可达性分析
二叉树
平衡二叉树
红黑树
B树
B+树
树
中间节点不保存数据只用来索引,所有数据保存在叶子节点
所有叶子节点包含了全部元素数据,及指向这些元素记录的指针,且叶子节点本身是依关键字的大小自小而大的顺序连接
所有中间节点的元素同时存在于叶子节点,在子节点元素中是最大(或最小)元素
B+树相邻的叶子节点之间是通过链表指针连起来的,B-树却不是
B+数中间节点没有卫星数据,所以同样大小的磁盘页可以容纳更多的节点元素,因此B+树比B树更加矮胖并减少磁盘IO
B树查询不稳定,最好时查询到中间节点,最坏时查到叶子节点,B+树很稳定一直查询到叶子节点,范围查找时,可以通过叶子元素间的索引快到找到数据
对比
内容
数据库和缓存一致性
技术知识
0 条评论
回复 删除
下一页