JAVA
2022-02-23 16:14:36 3 举报
AI智能生成
JAVA技术栈
作者其他创作
大纲/内容
服务器
Nginx
反向代理
负载均衡
日志切分
tomcat
jetty
JMS
并发编程
分工
Executor与线程池
FORK/JOIN
Guarded Susoension模式
Balking模式
Thread-Per-Message模式
生产者-消费者模式
Worker Thread模式
两阶中止模式
协作
信号量
管程
Lock&Condition
Synchronized
CountDownLatch
CyclicBarrier
Phaser
Exchanger
互斥
无锁
不变模式
线程本地存储
乐观锁-CAS
版本号机制
1、取出记录时,获取当前version
2、更新时,带上这个version
执行更新时,set version= newVersion where version = oldVersion
如果version不对,就更新失败
CAS中的ABA问题
原子引用
解决方法
对于对象加一个版本号控制
使用atomicStampReference
底层原理
使用CPU指令:Unsafe.compareAndSwapInt()
缺点
性能消耗大
只能保证一个共享变量的原子性
JDK8对cas的优化
Copy-on-write
原子类
互斥锁
Synchronized
Lock
读写锁
锁
synchronize
JVM的优化
偏向锁
发生的情况
没有竞争的情况
不同的线程都是在不同的时间请求的资源
特点
发现是偏向自己那么直接执行无需再cas或者和自旋
自旋锁
会自旋一段时间尝试获取
避免频繁升级成重量级锁
自适应自旋锁
自旋的次数和时间不是固定的,取决上个线程获取锁的情况而定
如果上次线程自旋20次就获得了资源,那么认为这个资源是比较好自旋后获得的,所以自旋的时间和次数会增加
轻量级锁
子主题
锁粗话
jvm会扩大锁定的代码范围从而提高性能
例子
sync锁在for循环之后,优化成提到for外部
锁消除
删除不必要的加锁操作,判断到一段代码中,堆上的数据不会逃逸出当前进程,那么可以认为这段代码是线程安全的,不必要加锁
重量级锁
需要将操作系统的用户层切换到内核层
耗费资源
锁的膨胀
膨胀过程
锁的标志位
volatile
线程
创建
集成Thread 重写run方法
实现Runable接口,实现run方法
实现Callable接口 重写call方法,用get获取返回值
线程池Excutors
四种实现方式
newFixedThreadPool
固定线程数
最大线程数=核心线程数
使用LinkedBlockingQueue
newSingleThreadPool
最大线程数=核心线程数 =1
newCacheThreadPool
最大线程数为Integer.MAX
核心线程数为0
空闲60s就回收
newScheduledThreadPool
集合框架
Map
原理图
共同特性
key不能重复val可以
分类
hashMap
扩容
hashMap扩容为什么是2倍
hash取模的写法为 (size - 1) & (key.hashCode() ^ (key.hashCode() >>> 16));
size -1 要为0111结尾的二进制可以减少碰撞概率 所以要尽量为偶数 用<<2 计算比较快
用&取余比用%更快
结构
数组+链表+红黑树
数据节点数据结构为Node<key,val>
int hash
K key
V val
Node next
关键参数
1.7和1.8的区别
插入方式
扩容方式
结构
无序
线程不安全
JUC包中有对应的线程安全类【ConcurrentHashMap】
treeMap
可以实现有序
实现一个比较器
linkedHashMap
是hashmap的一个子类,保存插入顺序
hashTable
区别最主要的就是hashTable是线程安全的
主要是通过synchronized修饰符实现的
替代品:ConcurrentHashMap
Set
HashSet
其实对hashMap包一层
treeSet
要实现一个比较器
LinkHashSet
list
arrayList
动态扩容
给定默认的初始化容量 为 10 ,但是new一个list的时候并不会初始化容量而是在add的时候初始化
扩容的触发时机
数组剩余的容量小于要插入的元素的数量
扩容的规则
newCapacity = oldCapacity + (oldCapacity >> 1)
容量扩大为原来的1.5倍
实现
基于动态对象数组实现
插入慢的原因
在数组中间插入数据,会导致此后的数据需要移动一位
到达容量阈值的时候,要做扩容
思考
数据量比较大的时候,采用尾插法以及指定无需扩容的list大小,那么插入性能会比LinkedList差吗?我看未必
测试
Vector
数组实现
线程同步
在方法上使用synchronized
需要线程安全的情况可以试用JUC 下的list
LinkList
链表结构
双向链表
线程不安全
查询速度
随机查询的速度确实比较差
原因
每个Node只能知道前后节点的位置所以只能按顺序去读取,如果是试用index随机查询的话,实际上还是要使用循环对比,直到得到对应的index,在位置处于中间的数据的时候会非常慢
优化
linkedlist为了查询快一点在获取index的时候还做了二分法查询,所以如果查询的是头尾节点的数据还是不慢的
MySql
数据库引擎
InnoDB
支持事务
MyISAM
不支持事务
MyISAM与InnoDB的区别
数据库锁
类型锁
悲观锁
意向排它锁
意向共享锁
排它锁
共享锁
适用场景:写多读少的情况
乐观锁
使用场景:读多写少的情况
级别锁
行锁
表锁
锁升级
索引
哈希索引
B+树索引
聚集索引
该索引中主键的逻辑顺序决定了表中相应行的物理顺序
主键就是聚集索引吗?
答案
辅助索引
该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同
Q1:B+树为什么比B树更适合做索引
全文索引
适合建索引的字段
为经常出现在关键字order by、group by、distinct后面的字段,建立索引
在union等集合操作的结果集字段上,建立索引
为经常用作查询选择的字段,建立索引
.在经常用作表连接的属性上,建立索引
高并发
措施
1、加索引
2、分表分库,读写分离
3、去掉外键
视图
理解:视图是已经编译好的sql语句是基于sql语句的结果集的可视化的表
视图和表的区别:
1、视图是窗口,表示内容
2、视图没有实际的物理记录,而表有
3、视图是虚表,表是实表
4、视图的建立和删除只影响视图本身,不影响对应的表
1、视图是窗口,表示内容
2、视图没有实际的物理记录,而表有
3、视图是虚表,表是实表
4、视图的建立和删除只影响视图本身,不影响对应的表
慢查询
定义:超过系统设置的long_query_time参数的sql语句
慢查询对于跟踪有问题的sql语句有很大的帮助
事务
四大特性(ACID)
原子性
要么全部做完,要么都不做
一致性
一致性也比较容易理解,也就是说数据库要一直处于一致的状态
隔离性
所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一
个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响
持久性
持久性是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也
不会丢失。
优化
硬件优化
系统配置
数据库表结构
SQL优化以及索引
定位问题SQL
通过MySQL慢查询日志对有效率问题的SQL进行监控
子主题
分析执行计划
使用 EXPLAIN 关键字可以知道MySQL是如何处理你的SQL语句的以便分析查询语句或是表结构的性能瓶颈。
通过explain命令可以得到表的读取顺序、数据读取操作的操作类型、哪些索引可以使用、哪些索引被实际使用、表之间的引用以及每张表有多少行被优化器查询等问题。
当扩展列extra出现Using filesort和Using temporay,则往往表示SQL需要优化了。
通过explain命令可以得到表的读取顺序、数据读取操作的操作类型、哪些索引可以使用、哪些索引被实际使用、表之间的引用以及每张表有多少行被优化器查询等问题。
当扩展列extra出现Using filesort和Using temporay,则往往表示SQL需要优化了。
SQL优化
Query
建立索引且简历在经常要group by、order By的字段上
尽量避免使用select * ,无用数据会减慢查询效率
尽量避免使用in、not in、or,in和or会导致数据库引擎放弃索引进行全表扫描
必要的话可以使用union进行操作,union不会导致索引失效
必要的话可以使用union进行操作,union不会导致索引失效
使用like操作时,不能用%xxx形式,但是可以用 like xxx%
尽量减少判空,可以在初始化时给字段一个默认值。
Insert
不要使用单条插入,使用批量插入会速度会更快
insert into 'table_a' ('a','b','c') values('x','x','x'),('c','c','c')
insert into 'table_a' ('a','b','c') values('x','x','x'),('c','c','c')
添加事务会使得插入操作速度更快
插入记录的主键有序会是速度更快,因为插入数据需要建立索引,有序的主键可以使得索引建立更快
如果是要插入非常大量的数据的话,这个表可以不建立索引,因为索引会导致更新速度变慢
索引优化
选择order\group By的字段设置索引
不以%xxx做统配
不适用or会导致索引无效
数据库表结构的优化
选择适合的数据类型
使用较小的数据类型解决问题
使用简单的数据类型(mysql处理int要比varchar容易)
尽可能的使用not null 定义字段
尽量避免使用text类型
表的范式的优化
分表
垂直拆分
把不常用的字段单独放在同一个表中
把大字段独立放入一个表中
把经常使用的字段放在一起
优点:拆分后业务清晰,拆分规则明确、系统之间整合或扩展容易、数据维护简单
水平拆分
解决数据量过大的问题,每个表的字段都是一样的
对ID进行hash运算,如果要拆分成5个表,mod(id,5)取出0~4个值
针对不同的hashID将数据存入不同的表中
问题:跨分区表的数据查询、统计及后台报表的操作等
好处:降低在查询时需要读的数据和索引的页数,同时也降低了索引的层数,提高查询速度
系统配置的优化
操作系统配置的优化
增加TCP支持的队列数
mysql配置文件优化
Innodb缓存池设置(innodb_buffer_pool_size,推荐总内存的75%)
缓存池的个数(innodb_buffer_pool_instances)
硬件优化
加CPU
加内存
加磁盘
SQL
连接
内连接
A INNER JOIN B ON A.XX=B.XX
左连接
A LEFT JOIN B ON A.XX=B.XX
右连接
A RIGHT JOIN B ON A.XX=B.XX
全连接
MySql没有全连接
FULL JOIN 或 FULL OUTER JOIN
分页
limit
参数:startIndex
参数:pageSize
删除
drop
drop语句将表所占用的空间全释放掉
delete
DELETE操作不会减少表或索引所占用的空间
truncate
表执行RUNCATE后这个表和索引所占用的空间会恢复到初始大小
存储过程
语句
create procedure 存储过程名字()
(
[in|out|inout] 参数 datatype
)
begin
MySQL 语句;
end;
(
[in|out|inout] 参数 datatype
)
begin
MySQL 语句;
end;
概念
存储过程是一个预编译的SQL语句,优点是允许模块化的设计,就是说只需创建一次,以后在该程序中就可以调用多次
调用
可以用一个命令对象来调用存储过程
可以供外部程序调用,比如:java程序
优点
存储过程是预编译过的,执行效率高
存储过程的代码直接存放于数据库中,通过存储过程名直接调用,减少网络通讯
安全性高,执行存储过程需要有一定权限的用户
存储过程可以重复使用,可减少数据库开发人员的工作量
缺点
移植性差
联合
Union
对查询得到的结果进行去重在返回
union All
联合之后直接返回结果
oracle
缓存系统
Mechached
数据类型
字符串
无法持久化
不能进行分布式扩展
Redis
数据类型
列表List
哈希Hash
字符串String
有序集合zSet
格式: zadd name score value
描述:Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
无序set
格式: sadd name value
描述:Redis的Set是string类型的无序集合。
持久策略
RDB
AOF
常用命令
Set
Expire
设置过期时间(单位秒)
返回负数表示已经不存在
Setex
设置key的值并且设置对应的过期时间
Mset
一次设置多个 key 的值,成功返回 ok 表示所有的值都设置了
Mechached
ZooKeeper
JVM
类加载器
Bootstrap
Extension
System or Application class loader
内存自动分配
定位引用
类的加载过程
加载
验证
准备
解析
初始化
当初始化一个类的时候,如果发现其父类还没有进行过初始化、则需要先初始化其父类
虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步。
内存自动回收
可达性分析
虚拟机栈(栈帧中的本地变量表)中引用的对象
方法区中类静态属性引用的对象
方法区中常量变量引用的对象
本地方法栈中JNI(即一般说的Native方法)引用的对象
回收内存
堆
方法区
GC 类型
Minor GC
Full GC
Major GC
垃圾算法
自我整理
性能调优
内存区域结构
程序计数器
虚拟机栈
栈帧
局部变量
操作数栈
动态链接
方法出口
本地方法栈
堆
方法区
运行时常量区
直接内存
直接内存和堆内存的比较
高并发
Spring
模块
Spring Core
Spring AOP
Spring Dao
Spring ORM
Spring Web
Spring MVC
核心容器
AOP
通知(advice)
前置通知(Before Advice)
返回之后通知(After Retuning Advice)
抛出(异常)后执行通知(After Throwing Advice):
后置通知(After Advice)
围绕通知(Around Advice)
切面(Aspect)
连接点(Joinpoint)
切入点(Pointcut)
原理
动态代理
jdk 动态代理
做一个拦截器和反射实现的
cglib动态代理
通过ASM框架动态生成class文件
区别
Spring事务
类型
编程式事务
声明式事务
隔离级别
ISOLATION_DEFAULT
ISOLATION_READ_UNCOMMOTED
ISOLATION_REPEATABLE_READ
ISOLATION_SERIALIZABLE
异常情况
脏读
事务A还未提交数据尚在缓存中就被事务B读走了
幻读
一次事务中读取到的数据数量不一致
不可重复读
一个事务中两次读取一个资源,结果不一致,未对资源加锁
依赖注入IOC
概念
依赖注入
反转控制
原理
技术
XML
反射
流程图
源码
获取扫描路径
获取包名
通过反射使用包名获取到对应的class类
判断得到的类是否有注解
初始化有注解的对象
利用反射机制,获取对象中的所有属性,查看属性中是否有存在注解
这个步骤其实也就是依赖注入
dubbo
架构
详解
registry
consumer
provider
monitor
配置
高可用
负载均衡
RandomLoadBalance(权重随机算法)
LeastActiveLoadBalance(最小活跃数负载均衡)
ConsistentHashLoadBalance(一致性 hash 算法)
RoundRobinLoadBalance(加权轮询负载均衡)
例子
服务降级
ock=force:return+null
mock=fail:return+null
读写容错
读容错:Failover
写容错:Failfast
dubbo原理
RPC原理
netty
基于JAVA NIO 多路复用模型
子主题
框架设计
启动解析、读取配置文件
服务暴露
服务引用
服务调用
缺点:dubbo的设计是为了适应并发高,数据小的情况,所以在大数据的情况下并不适用
分布式相关
分布式事务
用Redission实现分布式锁
对key进行hash
存到redis里面,设置过期时间
其他服务器获取时,顺带获取时间,不断轮询
redis是集群的话,可能会在主从同步时出现数据没有完全同步的问题
CAP
Consistency(强一致性)
Availability(可用性)
Partition tolerance(分区容错
性)
BASE定理
基本可用Basically Available
软状态 Solf state
最终一致 Eventually consistent
分布式一致性理论raft
jstorm
MyBatis
数据结构
表
栈
队列
树
类型
B+树
平衡二叉树
平衡树(B-树)
二叉查找树
区别
B-tree与B+tree的区别
b+树的中间节点不保存数据,所以磁盘页能容纳更多节点元素,更“矮胖”
要得到所有数据B+树对叶子节点进行遍历即可,而B树需要进行多次中序遍历
JDK8特性
Lambda表达式
格式
前提条件
方法的参数或局部变量类型必须为接口才能使用lambda表达式
接口中有且仅有一个抽象方法
实现原理
匿名内部类
表达式和匿名内部类的区别
所需类型不一样
抽象方法的数量不一样
实现原理不一样
接口增强
新增默认方法
格式
调用
新增静态方法
格式
调用
使用场景
如果需要被实现类重写则使用默认方法,否则使用静态方法
内置函数接口
常用
Supp
Consumer
Function
predicate
方法引用
格式
对象::方法
类名::静态方法
类名::普通方法
类名::new 调用构造器
string[]::调用数组的构造器
子主题
注意事项
被引用的方法 参数要和接口中的一直,返回值也是
stream流
获取流的两种方式
Collection类中有一个stream()方法
通过stream.of(...)
IO流
NIO
Channel
FileChannel
文件通道,用于文件的读和写
SocketChannel
把它理解为 TCP 连接通道,简单理解就是 TCP 客户端
DatagramChannel
用于 UDP 连接的接收和发送
ServerSocketChannel
TCP 对应的服务端,用于监听某个端口进来的请求
read()
就是将数据从channel读到Buffer中
write()
就是将数据从Buffer中写到Channel中
Buffer
缓冲类型
buffer子类
ByteBuffer
intBuffer
CharBuffer
LongBuffer
FloatBuffer
ShortBuffer
buffer属性
capacity
position
limit
子主题
属性值
capacity
limit
position
Seletor
初始化
Selector selector = Selector.open();
注册
channel.register(selector, SelectionKey.OP_READ);
注册类型
SelectionKey.OP_READ
SelectionKey.OP_WRITE
SelectionKey.OP_CONNECT
SelectionKey.OP_ACCEPT
IO
传统IO
字符流
Reader
BufferReader
CharArrayReader
InputStreasmReader
StringReader
FilterReader
Writer
BufferWriter
CharArrayWriter
StringWriter
OutputStreamReader
字节流
InputStram
FileInputStream
ByteArrayInputStream
FilterInputStream
DataInputStream
BufferInputStream
StringBufferInputStream
ObjectInputStream
OutputStram
ByteArrayOutputStream
FileOutputStream
DataOutputStream
BuffrtOutputStream
PrintStream
FilterIOutputStream
ObjectOutputStream
区别
面向对象
IO:流
NIO:缓冲
是否阻塞
IO:阻塞
NIO:非阻塞
是否有选择器
IO:无
NIO:有选择器
模型
IO多路复用
阻塞IO
非阻塞IO
信号驱动IO
异步IO
Redis
数据类型
String
Hash
List
set
命令
sadd
类型
zset
命令:zadd
命令:zrem
命令:zrevrank
子主题
优点
支持持久化
AOF
RDB
可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用
数据类型丰富
redis为什么这么快
单线程
纯内存
多路复用
redis过期策略&内存淘汰机制
例子
这个问题其实相当重要,到底redis有没用到家,这个问题就可以看出来。比如你redis只能存5G数据,可是你
写了10G,那会删5G的数据。怎么删的,这个问题思考过么?还有,你的数据已经设置了过期时间,但是时间到
了,内存占用率还是比较高,有思考过原因么?
redis采用的是定期删除+惰性删除策略
问题:
为什么不用定时删除呢
需要用一个定时器负责监控key,虽然可以及时的删除缓存,但是十分消耗CPU,在高并发的情况下,CPU要用来处理请求而不是清除key
策略
定期删除+惰性删除策略
定期清除是随机抽取key进行判断是否过期,过期了就会删除
惰性删除
在用户访问的时候会去判断这个key是否过期如果过期的话就会删除
内存淘汰机制
如果定期删除没删除key。然后你也没即时去请求key,
也就是说惰性删除也没生效。这样,redis的内存会越来越高
也就是说惰性删除也没生效。这样,redis的内存会越来越高
渐进式rehash
缓存穿透
概念
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
处理方案:
经过数据查询为空的数据,也存到缓存中为key-null 过期时间可以设置短一点;不宜过长,过长会导致正常的情况的也不可用
在接口层对数据做校验,未经验证的数据不让查
采用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的key,不存在的key直接被过滤;
缓存雪崩
概念
大量的key设置了相同的过期时间,导致数据在同一时间过期,请求频繁直接访问DB引起雪崩
处理方案
给每个key的过期时间再加一个随机值,使得每个key的过期时间是分布的
设置热点数据永不过期
MQ
使用场景
异步处理
应用解耦
流量削峰
消息通讯
JMS-Java Message System
优点
解耦
异步
可靠
消息模型
点对点
角色
生产者
将消息发送到消息队列中去存储
消费者
从队列中获取消息
消息队列
消息存储在队列中直到被消费或超时
特点
每个消息都只有一个消费者
发送者和生产者之间没有时间的依赖,生产者将消息发送到队列中不管接受者有没有在接受消息就可以继续消息的生产
消费者在成功获取到消息后需要向队列发送ack
模型图
子主题
发布订阅
角色
发布者 Publisher
订阅者
主题 topic
mq需要考虑的点
生产者发送信息确保不丢失
停止等待
回调处理
生产者生产消息的时候到mq服务上去注册一个回调,那么生产者就可以不断地发送数据。mq服务接受成功或者失败在通过调用回调请求反馈给生产者,从而提高了并发
消息丢失问题
rabbit如何防止消息丢失
消息持久化问题
消息重复消费问题
消息的幂等性
由于生产者是有可能存在重复发送同一个消息的情况,所以消费者需要做好幂等性校验
锁类型
偏向锁
轻量级锁
重量级锁
0 条评论
下一页
为你推荐
查看更多