- 使用关联查询(join)代替子查询,子查询会在内存中创建临时表来过滤数据给查询语句,相当于查询两次。而join只需要一次就可以完成查询动作
- 使用联合(union)查询代替手动创建的临时表
- 优化查询语句
- 使用合适的索引
- 选取适合的字段属性长度:一般来说数据库中表越小,查询越快,定义一个字段时,长度设置尽可能小,提高查询效率,尽可能把字段设置notNull,数据库查询时,不用去比较null值
- 分表、读写分离
- 配置的优化,最大并发数,缓存大小
- 索引是数据库高效查询的一种数据结构
- 在mysql InnoDB中,数据存储就是一个B+Tree树,表的主键就是树非叶子节点的key,叶子节点保存了key对应的具体数据,所以mysql InnoDB中,主键是必须存在的,如果不存在,会隐式的生成一个自增的主键ID
- 一般B+tree树高度是2-4层,理论上4次以内的IO查询就会找到数据
- 索引分主键索引、唯一索引、普通索引、联合索引等,除了主键索引,其它索引叶子节点保存的是这条数据对应的主键,所以走非主键索引的查询,会先获取主键,然后根据主键查询具体的值,对数据量小的表,可以不需要建索引,全表扫描会更快
- euraka 服务注册与发现
- openFeign 服务间的调用以及负载均衡,负载均内部是ribbon实现的
- zuul和gateWay 都可以做网关
- hystrix 服务降级以及熔断
- springConfig 分布式配置中心,可以和spring bus搭配使用
- redis 对访问频繁的热点数据做缓存,减少数据库IO操作,计数可以做sequece生成唯一主键、bitmaps还可以来统计一个数据是否访问过、GEO可以做地理位置相关的操作
- 消息中间件,主要用来系统间传递消息,具有削峰、填谷、以及系统间解耦。业务上有大量业务数据需要发给下游系统,如果考虑RPC的话,一个是频繁请求消耗过大,还有就是发送业务速度快与下游处理的速度,会导致数据处理不过来导致的失败,而使用中间件,可以拉数据,根据自己业务处理能力来消费消息
- 线程创建和销毁过程,都有性能开销,还可以控制线程数量。
- 使用场景:
- 异步任务处理的,不是主流程的,比如业务中,清算以后要下发明细,但是还需要明细计提数据
- 发服务号通知业务
- MQ消息消费
- 核心线程数
- 最大线程数
- 空闲线程存活时间
- 存活时间单位
- 工作队列 :ArrayQ 有界 LinkedQ 无界 synchronusQ不缓存任务的阻塞队列 prorityQ优先级的无界阻塞队列
- 线程工厂:设定线程名,是否守护线程
- 拒绝策略:callerRuns直接执行被拒绝的线程,如果县城池shutdown则抛弃 *Abort (默认) 丢弃抛异常 Discard 丢弃 DiscardOldest 丢弃最老的一个,并将新的加入
- 原子操作的Integer类,通过线程安全的方式操作加减
- thread
- runable
- callable
- 线程池
- 新建new
- 就绪runable
- 运行runing
- 阻塞blocked
- 死亡dead
- sleep不会释放锁,阻塞线程
- wait放锁,等待其它线程notify
- yield 暂停当前线程,线程重回就绪
- join 当前调用join方法,等join的线程结束后,程序继续
- 直接杀死线程,不安全, interrupt() 方法来中断线程比较好
- synchronized锁,多线程情况下,保证对实例变量线程安全
- synchronized可以加在方法上和同步代码块,synchronized 加方法上或者sychronized(this)锁的都是对象,会对其它锁对象的同步方法阻塞
- synchronized(非this)锁定代码块,其它同步方法是异步
- 加synchronized关键字的,编译后的class文件是有加锁和退出锁的操作的,每个对象有一个monitor监视器,调用获取对象时,将值+1,离开-1。加减表示锁占有
- 多个线程间对变量可见,加了这个关键字,每个线程对变量进行改变,都会把最新结果写回共享内存中,被其它线程可见
- 使用这个声明的变量,编译器会避免指令重排
- 指令重排 1。分配内存空间 2。初始化对象 3。将对象指向给刚分配的内存空间。2和3有可能重排序,多线程情况下,有可能出现问题
- ThreadLocal是一个本地线程副本变量工具类。线程间数据隔离
- 同步计数器,用来协调多个线程之间的同步
- 创建线程和销毁线程的花销是比较大,线程池管理线程,创建一定量的线程放在线程池,需要直接拿来调用
- 线程池参数
- corePoolSize:核心池大小
- maxmunPoolSize:线程池最大线程数
- keepAliveTime:线程没任务执行多久终止
- workQueue:阻塞队列,用来存等待执行的任务
- 线程池种类
- 单线程
- 固定线程大小
- 线程池中的队列
- 类加载系统
- 运行数据区(内存结构)
- 执行引擎
- 堆
- 方法区
- 栈
- 本地方法栈
- 程序计数器
- eden:新创建的对象放eden区,内存满了young GC,其他存活的对象转入s0区
- from(s0):from也满了后,也会触发young GC,未回收的转移到s1区,s1变成s0(复制算法)
- to(s1):转满了15次以后,还存活的转移到老年代
tenured space:老年代满了,会FULL GC(重量级的GC,调优主要调这个),(标记-清除算法,标记-整理算法) meta data
- 加载:将class文件从磁盘读到内存
- 连接
- 验证:验证字节码正确性
- 准备:给类静态变量分配内存,赋予默认值
- 解析:类装载器装入类所引用的其它所有类
- 初始化:给类静态变量赋予正确初始值,执行静态代码块
- 使用:
- 卸载:
- 引用计数器法:有地方引用 计数器+1,当引用失效,计数器-1。当计数器为0对象就不可能再被使用(相互引用永远不会被回收)
- 可达性分析法:一套根搜索算法,搜索类的引用链,如果没有被根节点引用,就是可回收的
- 常量池存在常量“abc”,如果没有任何String对象引用该字符串常量的话,说明常量“abc”是废弃常量
- 该类所有实例都被回收
- 加载该类的ClassLoader以被回收
- 该类对应的java.lang.class对象没有任何地方被引用
- 标记-清除算法
- 先标记可回收的内存区域,然后完成垃圾回收
- 缺点:1。效率不足,标记和清除效率都不高 2。空间问题,标记清除后会产生大量不连续的碎片
- 复制算法
- 为了解决效率,出现了复制算法,它把内存分为两块,每次只使用一块,当一块使用完以后,就将存活的复制到未使用的区域,然后清理当前空间(新生代 幸存者0和幸存者1算法)
- 缺点:每次有一般内存区域不能使用
- 标记-整理算法
- 根据老年代特点提出的一种标记算法,标记可回收的区域回收,并对存活内存进行内存整理,优点是内存区域连贯
- 缺点:代价比较大,会有停顿现象
- 分代收集算法
- 现有商用虚拟机基本都采用的一种算法,根据内存对象存活周期不同将内存分为几块(新生代、老年代)。
- 新生代中,每次收集都有大量对象死去,所以选择复制算法,只需少量复制成本完成垃圾回收
- 老年代对象存活几率较高,采用标记-清除 或者 标记-整理对垃圾回收
- docker类似一个虚拟机,可以让应用在其中部署运行,一次部署多处运行,减少运维压力
- 镜像 仓库 容器
- docker run -d -p 80:8080 container:id
- Lambda表达式
- 函数式接口 @FuntionalInterface
- stream
- LocalDate
- 接口中可以写静态方法
- 单例
- 简单工厂
- 模板方法
- 装饰者模式
- uname -a
- jdk
- 项目流程
- 项目中好的地方亮点 --> 配置化+3次运维+监听listener
- 自己在项目中解决了什么问题