type
status
date
slug
summary
tags
category
icon
password
Java基础
基本数据类型
数字:short,int,long,double,byte
字符:char
布尔:boolean
自动装箱拆箱
装箱:Integer i=1,Integer.valueOf(1)
拆箱:int a = i,i.intValue()
String
不可变因为final修饰,final char value[]
StringBuilder线程不安全,可变
StringBuffer线程安全,速度慢,可变
集合
List,Set,Map,Queue
ArrayList:线程不安全,指定位置插入,元素需要位移。
LinkedList:线程不安全,插入速度快。
HashMap:线程不安全,数组+链表。链表长度大于8,转为红黑树。
HasTable:线程安全,速度慢,基本被淘汰。数组+链表。
ConcurrentHashMap:线程安全,相对于HashTable实行分段加锁。效率上会快一些,底层数据结构还是跟HashMap一样。
线程状态
线程状态

死锁条件
- 互斥条件:该资源任意一个时刻只由一个线程占用。
- 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:线程已获得的资源在未使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。
- 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。
预防死锁
- 破坏请求与保持条件:一次性申请所有的资源。
- 破坏不剥夺条件:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
- 破坏循环等待条件:靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。
锁机制
乐观锁:认为每次访问时不会出问题,采用CAS更新数据。用于读比较多的场景。
悲观锁:认为每次被访问就会出问题,每次操作资源就会上锁。性能开销大,会有死锁问题。用于写比较多的常见。
并发编程
synchronized和reentrantlock,reentrantlock更加灵活。可实现公平锁。
Semaphore:信号量,获取到资源的时候才会继续执行。
CountDownLatch:到0之后开始继续执行。
CyclicBarrier:当一组线程全部到达屏障之后才会继续开始执行,否则都阻塞。
CompletableFuture:异步任务编排,anyOf和Allof并行执行,get方法阻塞。可以指定线程池。
线程池
ThreadPoolExecutor 3 个最重要的参数:
- corePoolSize : 任务队列未达到队列容量时,最大可以同时运行的线程数量。
- maximumPoolSize : 任务队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。
- workQueue: 新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中。
ThreadPoolExecutor其他常见参数 :
- keepAliveTime:当线程池中的线程数量大于corePoolSize ,即有非核心线程(线程池中核心线程以外的线程)时,这些非核心线程空闲后不会立即销毁,而是会等待,直到等待的时间超过了 keepAliveTime才会被回收销毁。
- unit : keepAliveTime 参数的时间单位。
- threadFactory :executor 创建新线程的时候会用到。
- handler :拒绝策略

垃圾回收

内存分配原则
- 对象优先在Eden分配
- 大对象直接进入老年代
- 长期存活的对象进入老年代
对象死亡判断方法
- 引用计数法:对象添加引用计数变量,每次被引用就+1。当引用计数等于0时被回收。
- 可达性分析法:从GC Root向下寻找,在这棵树上的就不需要被回收。
JVM调优
JVM内存区域

不得不进行调优的时机,这是最后手段,不建议优先使用。因为参数都是魔法数字,不可持续维护。
- full gc频繁,老年代太小
- gc停顿时间太长
- 系统启动的时候频繁gc,运行稳定之后不gc
排除方法
- jstat -gc查看堆中分区占用内存
常见策略
- 内存不够:Xms,Xmx设大点
- 启动时频繁gc:Xms=Xmx
- 调整内存区大小比例:survivor区和Eden区大小比率SurvivorRatio,新时代和老年代比例NewRatio
- 对象过早进入老年代:提升对象老年代年龄
- 垃圾回收器类型:Serial(串行),Parallel(并行),CMS,G1
设计模式
单例模式:Spring中Bean就是单例。
工厂模式:对象都通过工厂方法new出来,不用关心对象创建过程。
观察者模式/发布-订阅模式:MetaQ和EventBus
责任链:Spring中的Filer多个过滤器依次处理请求
Redis
常见数据结构:string,map,list,set,有序set
作用:分布式锁,限流,消息队列
限流
令牌桶算法:拿到令牌才能访问,定时向令牌桶中放置令牌。
缓存击穿,缓存穿透,缓存雪崩
缓存穿透:无效key即不在数据库里也不在Redis。布隆过滤器,接口限流。
缓存击穿:热点数据在数据库中,不在缓存中。提前预热热点数据。
缓存雪崩:缓存同一时间大面积失效。设置随机过期时间,提前预热。
主从复制
mater负责写,slave负责读
哨兵:多一个哨兵机器用于监听机器下线,选举出一个master。主观下线表示当前哨兵认为下线,客观下线所有哨兵认为该机器下线。
切片机器:适合数据量大的时候,主从复制有太多冗余,将数据切片分散保存。
持久化
AOF(Append Only File)保存每一个操作命令,不存在丢失数据风险,恢复速度慢。
RDB(Redis Database Snapshot)定时保存数据快照,存在丢失数据风险,恢复速度快。
混合模式:结合AOF和RDB的优点。
分布式锁
- 获取锁,set if not exist,如果key存在则获取失败。
- 释放锁,删除key。
- 需要设置过期时间,放在锁释放不了造成死锁。
Dubbo
生产者提供api包,不包括具体实现。消费者引入这个包直接使用。
- 注册中心(Registry):生产者在此注册并发布内容,消费者在此订阅并接收发布的内容。
- 消费者(Consumer):客户端,从注册中心获取到方法,可以调用生产者中的方法。
- 生产者(Provider):服务端,生产内容,生产前需要依赖容器(先启动容器)。
- 容器(Container):生产者在启动执行的时候,必须依赖容器才能正常启动(默认依赖的是Spring容器)。
- 监控(Monitor):统计服务的调用次数与时间等。
MySql
事务
ACID:原子性,一致性,隔离性,持久性
InnoDb
数据结构
- 二叉查找树:解决查询时间问题,二分查找
- AVL平衡树:解决二叉查找树不平衡问题,可能会退化为链表
- 红黑树:解决AVL旋转耗时问题
- B树:解决红黑树查询耗时问题,转为多叉查找树。降低树的层级。
- B+树:子节点用链表相连,非叶子节点不存储数据。
并发带来问题
- 脏读:A事务回滚了,B事务读了A回滚前的脏数据。
- 不可重复读:A事务在修改数据,B在修改前和修改后都读了一下,发现不一样。
- 幻读:B事务在A事务插入一行前读了一下,在插入之后读了一下,发现多了一行。
常见日志
- binlog:记录每一条更改数据库的SQL
- general query log:所有查询SQL
- slow query log:执行时间超过long_query_time的SQL查询
- redo log和undo log:事务日志
性能优化
- 分表分库
- 垂直分表:根据业务类型纵向切分表,根据访问业务,频率切分
- 水平分表:基于数据的表行进行拆分,将大表拆为几个小表
- 读写分离
- 主表写,从表读。从表利用主表的binlog复制数据
- 主从同步延迟:1)对数据一致性要求高的请求直接路由到主表读。2)提升从库的机器性能。3)延迟读取,等他同步完了
- 慢Sql优化
- 那些年我们一起优化的SQL
- 建立有效索引
- 避免索引失效
- 最左匹配
- 选择性过低
- 索引要高效
- 慢查询排查
- 开启慢查询日志slow_query_log,设置慢查询日志long_query_time
- select前加上explain
- 查看type和key,type至少要range以上
- const通过唯一索引找到
- range索引范围扫描
- index全索引扫描
- all全表扫描
Mybatis
#{}和${}区别是什么?
${}是字符串变量,有sql注入风险
#{}是参数变量,mybatis会将#{}替换为问号,执行前将问号替换为参数
如何分页
- 使用RowBounds,内存分页。原理是所有数据都加载到内存,把查询到的分页返回。
- 使用物理分页,使用mysql语句中的limit x,y。x是限制几条,y是偏移量。
常用标签
- 增删改查:insert,delete,update,select
- resultMap,用于解决java对象和数据库列名不一致问题
- where,when,if,forEach
SpringBoot
AOP
面向切面编程,可以将跟业务代码无关的逻辑放到AOP中实现。如:日志,权限控制,事务控制。
在方法执行前或者执行后插入代码。
IOC和DI
ioc:将对象的生命周期交给ioc容器管理,用于对象之间解耦
di:依赖注入,存在依赖的两个对象通过依赖注入连接。Autowired和Resource
鉴权和认证
RBAC模型
一个用户有多个角色,一个角色有多个权限。

表结构
一共5张表。用户表,角色表,权限表。用户和角色关系表。角色和权限关系表。
Spring Security
通用配置
- 拦截所有需要权限控制的路径,只放开跟登录有关的。
- 在UsernamePasswordAuthenticationFilter拦截器上自定义自己的拦截逻辑。
第一次登录
- 接收用户的帐号和密码,跟数据库中核对。
- 登录成功将生成的token放入redis中,value设置为用户信息
- 在前端cookie中塞入token
第二次登录
- 解析cookie中的token,如果在redis中存在则之间返回登录成功。
鉴权
- 根据用户名查询用户角色和权限,将权限列表塞回给User对象。Spring Security会校验访问的接口路径是否在权限列表中。
- 使用hasAuthority和hasRole注解控制权限。
定时任务
单机任务
spring的schdule
分布式任务
xxl-job
实时消息推送
- 轮询
- SSE:前端开启EventSource文件流,像断断续续的下载
- WebSocket:双选通信