读书笔记 1 --《码出高效:java开发手册》
书籍源码:
https://github.com/alibaba/p3c
第一章:
一、0和1的世界
1、位换算
1位 = 1bit (1b)
8b = 1Byte (1B)
1024B = 1KB
1024KB = 1MB
1024MB = 1GB
1024GB = 1TB
1024TB = 1PB
2、位操作
2.1、~ 按位取反
2.2、& 按位与(有0得0) (逻辑与“&&”有短路功能)
2.3、| 按位或(有1得1) (逻辑或“||”有短路功能)
2.4、^ 按位异或(相同为0,相异为1)
3、浮点数
3.1、定义
定点数:小数点固定。
浮点数:由符号位、有效数字、指数三部分组成。
3.2、科学计数法
采用科学计数法来近似表示一个极大或者极小且位数较多的数。
(符号位)a*10^n :
a:有效数字,1 <= |a| <10。
n:指数决定小数点的位置。
3.3、浮点数
业界流行标准:IEEE754,规定了4种类型:单精度,双精度,延伸单精度、延伸双精度。
单精度:float 4B
双精度:double 8B
(重点)3.4、使用注意事项:
由于浮点数存在精度缺失的问题。因此:
A:禁止通过判断两个浮点数是否相等来控制某些业务流程。
B:在数据库中保存小数时,使用decimal类型。
二、TCP/IP
1、四层网络模型
1.1、链路层(IEEE 802)
以字节为单位把0与1进行分组。
1.2、网络层(ip)
根据ip寻找机器。
1.3、传输层(tcp)
根据端口找到应用。
1.4、应用层(http)
根据协议解析为能识别的数据。
2、协助方式:
应用层按协议打包数据;传输层加上双方的端口;网络层加上双方的ip地址;
链路层加上双方的MAC地址,并将数据拆分成数据帧。
第四章:走进JVM
1、内存布局
1.1、Head 堆区
Young Garbage Collection : YGC
当Eden区装满的时候,触发YGC;存活的对象,进入s0;下一次YGC的时候,GC的对象为:Eden,s0;
存活的对象,进入s1。
大对象:
创建的时候
a、Eden空间不足,则在老年代创建。
b、GC的时候,Servivor空间不足,直接进入老年代。
Full Garbage Collection : FGC
当老年代空间不足时,触发FGC。
1.2、元空间(Metaspace)
废弃永久代的原因:
1、JVM启动时,固定大小,难以调优。(-XX:MaxPermSize=1024m)
2、FGC会移动类元信息。
3、动态类的创建是在永久代,因此过多的创建动态类,会造成永久代的OOM。
元空间:
1、在本地内存中分配。
2、存储的内容:类元信息,字段,静态属性,方法,常量。(字符串常量在堆中)
2、垃圾回收
2.1、G1
a:将堆分为n个:Eden、Servivor、Old。
b:YGC时不再进行s0/s1的交换。
第五章:异常与日志
异常:
1、思考的问题点:
1.1、哪里发生异常?
1.2、谁来处理异常?
1.3、如何处理异常?
2、异常的捕获:
2.1、需要分清哪些是稳定代码,禁止try-catch稳定代码。
3、异常的处理
3.1、谁来处理异常: 自己能否处理?自己是否需要处理?
日志:
日志规范:
1、日志的目的:
1.1、记录操作轨迹。
1.2、监控系统运行状态。
1.3、回溯系统故障。
2、日志规范
2.1、日志占位符,减少字符串的拼接。
2.2、additivity=false 禁止日志的重复打印。
2.3、区别对待错误日志:error记录系统错误,重要的业务错误。
2.4、记录完整的日志:
3、日志三问:
3.1、日志是否有人看?
3.2、看到这条日志能做什么?
3.3、能不能提升问题排查效率?
日志框架
1、日志框架的角色
1.1、日志门面:统一对外的接口,对调用者屏蔽细节。主流:slf4j,commons-logging
1.2、日志适配器:
适配器分两种:
1.2.1、日志门面适配器:
1.2.2、日志库适配器:
1.3、日志库:实现了日志的功能;主流:log4j,log-jdk,logback
第六章:数据结构与集合
数据结构
1、数据结构:数据的组织方式与其对应的处理方式。
2、数据结构分类:
2.1、线性结构:顺序表、链表、栈、队列等
2.2、树结构:
2.3、图结构
2.4、哈希结构:特定的哈希函数使两者关联。
3、算法复杂度:
时间复杂度(最好 --> 最差): o(1) < o(log^n) < o(n) < o(nlog^n) < o(n^2) < o(n^3) < o(2^n)
集合
1、fail-fast机制
遍历前,将集合长度存储到A中;遍历过程中,每次获取元素都判断一下A是否跟现有的长度相等;
如果不相等,就抛出ConcurrentModificationException,即fail-fast。
2、Map
2.1、树
2.1.1、高度:节点到叶子节点最长的边数。
2.1.2、深度:节点到跟节点的边数。
2.2、二叉树
2.2.1、至多有两个子节点的数称为二叉树。
2.2.2、平衡二叉树
性质:
a:树的左右高度差不能超过1
2.2.3、二叉查找树
性质:
a:一个节点,左子树上所有的节点值,都小于该节点。
b:右子树所有的节点值,都大于该节点。
查找:
根据判断值,往左还是往右继续查找,相等就为找到。
遍历方式:
a:前序遍历:根节点,左节点,右节点。
b:中序遍历:左节点,根节点,右节点。
c:后序遍历:左节点,右节点,根节点。
(左节点一定比右节点先被遍历)
2.3、红黑树
2.3.1、AVL树
a: 左旋
b: 右旋
2.3.2、红黑树
a:节点增加属性来标识节点的颜色,红色或黑色。
b:根节点必须是黑色。
c:所有NIL节点都是黑色的。NIL,即叶子节点下挂的两个虚拟节点。
d:一条路径上不能出现相邻的两个红色节点。
e:在任何递归树内,根节点到叶子节点的所有路径上包含相同数目的黑色节点。
(有红必有黑,红红不相连)
3、TreeMap 红黑树的实现
4、HashMap
4.1、多线程操作,出现如下问题:
4.1.1、死链
死循环。
4.1.2、扩容数据丢失
已经被rehash的链表,新增数据时,会丢失。
第七章:并发与多线程
1、并发环境需要考虑的问题:
1.1、并发程序之间有相互制约的关系。(共享资源的竞争)
1.2、并发程序的执行过程是断断续续的。(cpu时间片结束,记录线程现场与执行点。)
1.3、多少的并发才是合适的?(需要根据具体的机器来判断)
2、保证高并发场景下的线程安全需要考虑的问题:(要么只读,要么加锁)
2.1、数据单线程内可见。(单线程总是安全的!)
2.2、只读对象。
2.3、线程安全类。
2.4、同步与锁机制。
3、JUC(java.util.concurrent)
3.1、线程同步类:Object.wait()、notify();CountDownLatch(计数);Semaphore(信号量);CyclicBarrier(拦栅)
3.2、并发集合类:ConcurrentHashMap,CopyOnWriteArrayList,BlockingQueue
3.3、线程管理类:Executors,ThreadPoolExecutor,ScheduleExecutorService(定时任务)
3.4、锁相关类:Lock及其派生类。
4、锁
4.1、分类:悲观锁;乐观锁;偏向锁;分段锁。
4.2、锁主要提供了两种特性:互斥性和不可见性。
4.3、并发包中的锁
4.3.1、Lock是JUC包的顶层接口,不用synchronized,而是用volatile的可见性。
4.3.2、AQS(AbstractQueuedSynchronizer)定义了一个 volatile int state;作为共享资源,如果线程获取资源失败,则进入同步FIFO队列中等待;如果获取资源成功,则执行临界区代码。
执行完成后,通知同步队列中等待的线程来获取资源后出队并执行。
4.3.3、ReentrantLock 用 AQS 来实现锁,state来处理可重入锁逻辑,获得锁初始化为1,重入就累加,释放锁就递减,为0释放锁。
4.3.4、StampedLock jdk8提供的改进型读写锁。
4.4、synchronized(监视锁)
4.4.1、偏向锁:偏向于第一个获得它的线程。(实现方式:在监视锁中记录上次使用该锁的线程)
4.4.2、底层实现为:JVM底层通过监视锁来实现synchronized。监视锁(monitor),每个对象与生俱来的一个隐藏字段,JVM回根据synchronized的当前使用环境,找到对用对象的monitor,
再根据monitor的状态进行加、解锁的判断。
4.5、线程同步
4.5.1、volatile
4.5.2、信号量同步
5、同步
5.1、同步的原因
a、资源紧缺(线程共享CPU)
b、共建需求(共享变量)
5.2、可见行
a、volatile 的实现方式是:无副本。
b、锁的实现方式为:获取锁时创建副本,释放锁时,写回内存。
5.3、volatile
1、适用:一写多读。
6、线程池
6.1、为什么需要线程池
1、频繁创建线程,销毁线程会浪费大量的系统资源。
2、服务器负载过大时,让线程等待或者友好的拒绝服务。
3、实现主次线程隔离,定时任务,周期执行等。
6.2、ThreadPoolExecutor
6.3、ThreadLocal
1、内存模型
2、弱引用
3、哈希算法
6.4、引用类型
1、强引用:Object object = new Object();
2、软引用:
3、弱引用:YGC时,被回收。
4、虚引用:
6.5、弱引用和ThreadLocal
1、当ThreadLocal=null;时,Entry的Key会自动在下一次YGC时被回收。
2、ThreadLocla使用get,set时,又自动将key==null的value置为null。使value能被垃圾回收,避免内存泄漏。
3、但是实际使用ThreadLocla对象时,通常作为私有静态变量使用。因此它的生命周期不会随着线程结束而结束。
6.6、父线程变量传递给子线程
6.7、ThreadLocal 副作用
在线程池内使用ThreadLocal引发的问题:线程池有内存复用和内存常驻两个特点。
1、脏数据
2、内存泄漏,因:ThreadLocal 引用不释放。解决办法:remove() 方法。
第八章:单元测试
1、作用
1、提升软件质量
2、促进代码优化
3、提升研发效率
4、增加重构自信
2、单元测试的基本准则
AIR原则
1、A (Automatic 自动化)
2、I (Independent 独立性)
3、R (Repeatable 可重复)
3、如何规划
1、粒度小
2、方法级别
3、不负责跨类跨系统的交互
4、BCDE原则
1、B:Border,边界值测试。
2、C:Correct,正确的输入。
3、D:Design,文档驱动。
4、E:Error,错误校验。
5、Mock 屏蔽掉依赖。
常用的框架有 JMockit,EasyMock,JMock,
6、单元测试覆盖率
7、实战
1、断言(assert):封装好了常用的判断逻辑,当不满足条件时,该测试用例会被认定为测试失败。
2、假设(assume):当条件不满足时,测试会直接退出而不是认定为测试失败。
8、AssertJ 流式编程
第九章:
1、聊聊成长
没有捷径。
2、方法论
1、搜集,收集见闻。
2、整理,思考整理属于自己的。
3、专题,总结提炼,输出。
4、哲学,哲学方法论。