Java整体知识架构详解-之进阶篇一
2019-04-17 22:04:00 20 举报
AI智能生成
此为java整体知识架构的进阶篇,目标是整理java延伸出来的高级知识点、架构、优化以及中间件等,会更多探讨现在流行的分布式架构的选择和运用
作者其他创作
大纲/内容
并发编程
多线程实现方式
实现Runnable接口
创建单个线程的常用方式,实现接口即可
继承Thread
通过继承方式实现的线程,由于java的单一继承性,这种方式有局限性
Callable+FutureTask
一个线程执行有返回结果
Callable+ExecutorService+Future
多线程执行有返回结果的任务
线程池
线程池参数
corePoolSize
线程的核心线程数,当任务到来时,若创建的线程数量还未达到核心线程数,则会创建新的线程来处理
当任务到来时,若创建的线程数大于等于核心线程数且小于最大线程数,则只有当workQueue满是才创建新的线程去处理任务
当corePoolSize和maximumPoolSize相同,则创建的线程池大小固定,判断workQueue未满则加入workQueue中等待空闲线程去处理
当运行的线程数等于maximumPoolSize,且workQueue已经满了,则通过handler所指定的策略来处理任务
maximumPoolSize
最大线程数
workQueue
等待队列,当任务提交时,线程池所有线程正忙,会将该任务加入worker队列中等待
KeepAliveTime
线程池维护线程所允许的空闲时间,这个时间针对的是超过corePoolSize数量的线程,它们执行完线程不会立即销毁,直到超过KeepAliveTime所指定的时间
threadFactory
用来创建线程,默认创建的线程拥有相同的优先级且是非守护线程,同时设置线程的名称
handler
概述
该参数用来表示超过线程池执行任务限制的任务,我们所采取的策略,有四种实现
策略
AbortPolicy
直接抛出异常,默认策略
CallerRunsPolicy
用调用者所在的线程来执行任务
DiscardOldesPolicy
丢弃阻塞队列中靠前的任务,并执行当前任务
DiscardPolicy
直接丢弃任务
优点
降低资源消耗,重复利用已创建的线程降低线程创建和销毁造成的消耗
提高响应速度,任务到达是不需要等待线程创建就能立即执行
提高线程的可管理性,线程是稀缺资源不能无限制创建,通过线程池统一分配可以调优和监控
注意点
shutdown和shutdownNow
shutdown会将正在执行的任务执行完后再关闭,没被执行的任务则中断
shutdownNow会中断现在执行着的任务,没被执行的任务则返回
线程知识点
线程中断interrupted
调用interrupted并不是说该线程立即中断了,需要配置isInterrupted来使用
ThreadLocal
用空间换时间,表示把变量在每个线程存储一份进行操作
NIO
核心组成
Buffer
一块缓存区,存储字节数组,维护一些变量实现数据反复利用
Channel
双向可异步读写,数据读到缓存Buffer中
Selector
通过单一线程控制一个Selector,并把请求数据转发到多个Channel通道进行传输
概述
NIO操作面向缓冲区,数据从Channel读取到Buffer缓冲区,随后在Buffer中处理数据
原子操作
基本类型
AtomicBoolean
AtomicInteger
AtomicLong
数组
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray
引用类型
AtomicReference
包装对象进行cas操作
AtomicReferenceFieldUpdater
对对象中的字段进行cas操作
并发工具类
CyclicBarrier
栅栏,若设置5个栅栏表示当只有5条线程执行到await方法时才会继续执行
CountDownLatch
计数器,使用await阻塞,当计数器减为0时,才可以唤醒线程继续执行下去
semphore
信号量,有几个信号量就表示允许几个线程同时执行,超出的执行线程会阻塞
算法
海量数据处理问题
分而治之/Hash映射+HashMap统计+堆/快速/归并排序
例如海量日志提取访问百度次数最多的IP地址
多层划分
Bloom filter/Bitmap
Trie树/数据库/倒排索引
外排序
子主题
排序算法
排序算法类别
选择排序
稳定性
不稳定
时间复杂度
O(n2)
概述
先遍历原数组,取第一个数,和后续的数据对比,找到较小的数的位置,在继续和后续数据对比,直到找到最小的,和第一个数交换位置,再取第二个数重复上述步骤
插入排序
稳定性
稳定
稳定
时间复杂度
O(n2)
时间复杂度
O(n2)
O(n2)
概述
从左至右相邻两个数进行对比,后个数小往前移,不断往前两个两个对比,直到小的数比前一个数大,再回到开始时对比的两数继续往后两两对比
冒泡排序
稳定性
稳定
时间复杂度
O(n2)
概述
遍历两两对比,将最大的数往后冒
快速排序
稳定性
不稳定
时间复杂度
O(nlogn)
概述
随意从数组中抽个值作为基点A,第一个数位置记为i,最后一个数记为j,i向右移动,j向左移动,当碰到i对应的数大于基数A,停下i;当j对应的数碰到小于基数A停下,交换i,j对应的数;知道i,j碰到一起,判断碰到一起的数大于基数A,,且在A左侧则两者交换位置;以碰到位置将数组分成两组,执行相同的上述步骤,最后数组就是从小到大排列了
归并排序
稳定性
稳定
时间复杂度
O(nlogn)
概述
分而治之的思想,先全部打散了,再用一个大数组一遍排序
堆排序
稳定性
不稳定
时间复杂度
O(nlogn)
通过最大堆顶的形式,每次堆排序的最大堆顶值和末尾倒数没和堆顶交换过的数交换,经过数次堆排序得出结果
希尔排序
二叉树排序
计数排序
桶排序
基数排序
稳定性
简单的说就是排序前后,值相同的两个数前后位置会不会倒过来,倒过来了就不稳定,还是原来的顺序就稳定
UML
概述
架构师必备技能,画出实体间的耦合关系
关联关系
1. 单向关联
单向不封闭空心箭头表示,has的关系,比如顾客和他地址的关系,顾客有地址这属性
2. 双向关系
不带箭头直线便是,双方各自持有对方类型的成员变量,比如顾客持有产品列表属性,而产品列表持有哪些顾客购买属性
3. 自关联
单向不封闭空心指向自身箭头表示,也就是说自己包含自己类型的成员变量,比如链表节点,它包含的自己类型的下一个链表节点
4. 聚合关系
从空心菱形出发到不封闭空心的实线箭头表示,强调整体包含部分,但部分可以脱离整体存在,比如汽车包含发动机,但发动机也是个实体可以单独存在
5. 组合关系
从实心菱形到不封闭空心的实线箭头表示,这里的部分不能脱离整体,强调has的概念,比如嘴是头的一部分,不能脱离头单独存在
6. 依赖关系
虚线箭头表示,表示依赖对象才可执行,方法需要传入依赖的对象,比如说司机开车的动作,需要依赖车这个对象
7. 继承关系
对象继承extends后面的类为被指对象,继承者封闭空心实线箭头指向被继承对象
8. 接口实现关系
implement关键字后方接口为被指向对象,实现对象用虚线空心箭头指向接口
开发必备
前端长连接
WebSocket
最流行的web前端长连接技术
可能遇到的问题
tomcat已经对WebSocket端点集成,所以在使用tomcat部署war包的时候,不需要加上ServerEndpointExporter实例;如果用springboot的jar包形式启动,忽略这个问题
没过一段时间自动断开,这应该是它的空闲超时机制,当空闲时间超过一定值会自动断开,nginx的超时时间设置也会导致这个问题,可以采用定时重连,或者在close方法里进行断线重连
Netty
Netty也可以实现WebSocket长连接
Mybatis
缓存
一级缓存
mybatis的一级缓存是sqlSession级别的,它会创建一个私有的hashmap作为缓存容器
mybatis默认开启一级缓存
在同一个sqlSession中,执行两次相同的查询sql,第二次会从缓存读取;
在同一个sqlSession中,任何增删改都会导致缓存失效
当一个sqlSession结束后,缓存也会清除
二级缓存
mybatis二级缓存是mapper级别的,同一个mapper中,多个sqlSession共用同一个二级缓存区域
mybatis默认不开启二级缓存
在同一个mapper中,不同的sqlSession两次执行相同的sql语句,第二次之后也从缓存中读取
同一个mapper中,不同sqlSession执行任何增删改都会导致整个mapper二级缓存清除,所以对于存在大量增删改的数据表并不适合开启二级缓存
性能优化
MySQL性能优化
count(主键)往往是性能最优的
索引失效的情况
字符串不加单引号,会失效
使用的索引列不是复合索引列表中的第一部分,会失效
避免where子句中对字段进行null值判断,否则可能导致mysql放弃使用索引全表扫描
字段尽量加上默认值,比如0,''
尽量避免where子句中使用!=或<>操作符
避免where子句中使用or来连接条件(若or前的条件有索引,后面的列没有索引,那么涉及的索引都不会被用到),可以用union all来代替
避免在where条件中like以%打头
避免在where子句中对字段进行表达式操作
避免where子句中对=左边字段进行函数操作
开启mysql慢查询,配置慢查询时间,超过执行时间的语句将会记下来
需要事务处理的表使用innoDB,不需要的可以使用MyIsam,查询效率更高
group by后面的字段会默认进行排序,如果不想有这个损耗,可以用order by null来避免
重复执行相同的sql语句,传入参数中条件最好用外部传入,这样可以使用到mysql自己的缓存,比如where条件里包含日期字段=curdate(),这个curdate()最好外部传入,否则mysql每次都会执行一遍
JVM调优
堆设置主要设置初始堆内存,最大堆内存,年轻代和年老代比例,年轻代中Eden区和Survivor区的比值
年轻代过小会导致Minor GC过于频繁,影响系统性能;年老代过小会导致内存溢出;所以要根据业务需求适当配比年轻代和老年代
垃圾收集器也可以根据实际情况进行适当的选择,现在常用的为CMS(追求最短时间停顿)和G1收集器(适用大容量内存(大于4G))
Web安全
SQL注入攻击
避免直接拼接SQL,尽量使用成熟框架,比如MyBatis,xml中尽量不要使用$开头参数注入
避免直接拼接SQL,尽量使用成熟框架,比如MyBatis,xml中尽量不要使用$开头参数注入
CSRF攻击
概述
跨站点请求伪造,CSRF攻击常常还伴随着XSS攻击,本质是伪造用户请求达到非本用户访问该用户才有权限的接口
解决方案
强制用户和服务器交互,填写验证码
使用POST请求,更加不容易伪造,更易暴露
XSS攻击
概述
脚本攻击,比如用户提交的评论内容里包含了一段脚本,提交后,打开该页面会自动运行该脚本,这就是没处理好XSS问题
解决方案
在服务请求的时候加一层过滤即可,网上方案很多,只要意识到这点很容易解决,像Spring Security也提供了快捷的解决方案
DDOS攻击
概述
本质上是流量攻击,服务器带宽受不住就崩溃了,这也是最难防御的攻击
改善方案
nginx限流,对同一个ip的大量请求进行限制
权限验证
Spring Security
权限控制颗粒度较细,实现复杂
Shiro
权限控制颗粒度较粗,实现简单
Oauth2.0
接口授权协议,可以用spring-security-oauth2来实现
防盗链
使用Refered请求头判断,是否来自自己的域名
nginx限制ip
跨域
概述
跨域本质上是浏览器自己的防护
解决方案
前端使用JSONP,只能是POST请求
后端接口添加header请求头设置Access-Control-Allow-Origin
nginx域名转发
现在常用的Springboot添加注解
DevOps
0 条评论
下一页