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