最近浏览了一下阿里巴巴的Java开发手册,感受内容确实很是的赞,发现了很多本身在编程中的误区,所以决定经过成文牢固掌握,文中将选取我的认为比较重要的部分进行描述与分析。”愿站在巨人的肩膀上,码出高效,码出质量“。前端
手册中内容不少,包括编码规约、工程结构、MySQL数据库、异常日志、安全规约、单元测试等6大部分。其中工程结构部分在总体上对项目进行了把控,编码规约和MySQL设计规约中有很是多的“最佳实践”,我的认为是最为有价值的部分。次重点安全规约很符合互联网场景的须要,异常日志和单元测试部分相对来讲内容和价值相对小一点。
下图是我的对手册的简单汇总(将图片拖到浏览器新开页面,以后放大能够清晰不少),其中红星表示重点,黄色表示次重点。此外,其中的集合处理、并发处理、MySQL规约和工程结构有必定理解难度,会专门放到重难点加强一节进行详细分析。固然这只是我的的浅见,完整部分请见最下方的参考资料,目前阿里公司已推出这套规约的IDE插件,你们能够试试。git
Open Interface:提供RPC或Restful风格的接口,并经过框架进行网关安全控制、流量控制等。
终端显示层:前端模板渲染并执行显示的层。
Web Layer: 主要是对访问控制进行转发, 各种基本参数校验, 或者不复用的业务简单处理等。
Service Layer:业务逻辑服务层。
Manager Layer:这一层比较有意思,既包含了常见的外部接口的Agent功能,也包含了对DAO接口的简单封装用于复用,还能够在改为构建对于DAO的缓存。
DAO Layer:与底层 MySQL、Hbase等进行数据交互,一般基于各种DAL框架。
ExternalInterface: 包括其它部门 RPC 开放接口, 基础平台, 其它公司的 HTTP 接口。
Tip: 实际项目中彻底能够遵循该模式构建包的层次。github
集合操做一直是一个关键点,常见的小技巧包括经过Set元素惟一的特性,能够快速对一个集合进行去重操做,JD8中经过steam流对集合操做作了不错的加强。合理利用好集合的有序性 (sort) 和稳定性 (order) ,避免集合的无序性 (unsort) 和
不稳定性 (unorder) 带来的负面影响,ArrayList是order&unsort;HashMap是unorder&unsort;TreeSet 是order&sort。
TIp: 不一样类型Map集合K/V能不能存储null值的状况以下表所示sql
合理的经过并发控制来高效利用系统资源是工程师永远的追求,该手册的很多要求很好的认识到本身在该方面的不足。
线程池的建立
过去一半都经过Executors 去建立线程池,实际上这是不合理的,好比FixedThreadPool的阻塞队列大小Integer.MAX_VALUE,很容易形成大量请求的堆积,形成OOM。而ScheduledThreadPool容许线程的数量为Integer.MAX_VALUE,更加容易出现OOM。所以必须使用ThreadPoolExecutor建立线程池,明确的制定线程池的参数。
使用锁的原则
1.高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁 ; 能锁区块,就不要锁整个方法体 ; 能用对象锁,就不要用类锁。
2.对多个资源、数据库表、对象同时加锁时,须要保持一致的加锁顺序,不然可能会形成死锁。
3.并发修改同一记录时,避免更新丢失,须要加锁。要么在应用层加锁,要么在缓存加锁,要么在数据库层使用乐观锁,使用 version 做为更新依据。若是每次访问冲突几率小于 20%,推荐使用乐观锁,不然使用悲观锁。乐观锁的重试次数不得小于 3 次。
CountDownLatch
使用 CountDownLatch 进行异步转同步操做,每一个线程退出前必须调用 countDown方法,线程执行代码注意 catch 异常,确保 countDown 方法被执行到,避免主线程没法执行至 await 方法,直到超时才返回结果。须要注意子线程抛出异常堆栈,不能在主线程的try-catch块中捕获到。
ThreadLocalRandom
避免 Random 实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一seed 致使的性能降低,推荐使用ThreadLocalRandom。
Volatile
volatile 解决多线程内存不可见问题。对于一写多读,是能够解决变量同步问题,可是若是多写,一样没法解决线程安全问题。在完成饱汉的单例模式时,可使用Volatile关键字实现延迟初始化。
LongAdder
对于count++操做,可使用AtomicInteger count = new AtomicInteger();
,JDK8中推荐使用LongAdder,经过减小乐观锁的重试次数提升性能。
HashMap
HashMap 在容量不够进行 resize 时因为高并发可能出现死链,致使 CPU 飙升,在开发过程当中可使用其它数据结构或加锁来规避此风险。
ThreadLocal
ThreadLocal 对象建议使用 static修饰。这个变量是针对一个线程内全部操做共享的。数据库
数据库方面的优化一直困扰着我,书上的一下几个原则给予我的在数据库优化方面很多启示。
索引长度
过去一直没有注意过索引还有长度这个概念,如今才知道在varchar等类型字段上创建索引时,能够指定索引长度,达到必定区分度便可,通常对于字符串类型数据,长度为 20 的索引,区分度会高达 90%以上,可使用count(distinct left( 列名, 索引长度 )) / count( * )
的区分度来肯定。编程
此外页面搜索严禁左模糊或者全模糊,若是须要请走搜索引擎来解决。索引文件具备B-Tree的最左前缀匹配特性,若是左边的值未肯定,那么没法使用此索引。
order by
在有order by的场景,请注意利用索引的有序性。例如where a =? and b =? order by c的索引为a _ b _ c
覆盖索引
利用覆盖索引能够减小原表查询,经过索引页(目录)便可查到所需信息。一般来讲,可以创建索引的种类包括主键索引、惟一索引、普通索引,而覆盖索引是查询的一种效果,能够经过explain查看到extra 列会出现using index 。浏览器
分页查询
MySQL并非跳过offset行,而是取 offset + N 行,以后放弃offset行,返回所需N行,当数据量大时,推荐以下方式进行优化。先快速定位须要获取的 id 段,而后再关联:
SELECT a.* FROM 表 1 a, (select id from 表 1 where 条件 LIMIT 100000,20 ) b where a.id=b.id
SQL 性能优化的目标
至少要达到 range 级别, 要求是 ref 级别, 若是能够是 consts最好。
consts 单表中最多只有一个匹配行(主键或者惟一索引),在优化阶段便可读取到数据。
ref 指的是使用普通的索引 (normal index) 。
range 对索引进行范围检索。
tip: type = index,索引物理文件全扫描,速度很是慢,这个 index 级别比较 range 还低,与全表扫描是小巫见大巫。缓存
在Mysql Workbench中表述稍微有些区别:consts没变,Non-Unique Key Lookup表示ref, Index Range Scan表示range, full table Scan表示All, full index scan表示index,固然也能够选择Tabular视图替代Visual视图。安全
组合索引
区分度最高的在最左边,对于where a =? and b =?
来讲,a 列的值越惟一越好。此外,存在非等号和等号混合判断条件时, 在建索引时, 请把等号条件的列前置。
隐式转换
防止因字段类型不一样形成的隐式转换,致使索引失效,当数据查询超时,也须要把此做为很重要的考虑部分。性能优化
参考资料