Java核心编程知识索引

这篇索引并不会介绍过多语言层面的基础概念,侧重点主要在于 JVM 和 JUC 这两块,属于 Java 中比较进阶的知识了,我的知识也主要来自于两本书:《深入理解Java虚拟机》和《Java并发编程的艺术》以及网上搜集的资料,这两本书写的非常棒,入门是够了,通篇基本没废话,我的笔记也基本都是摘录自这两本书。
也正是如此,相关总结就直接放到 Github 了,不抄到这里了,这一篇主要来列一个大纲,以及做一些补充。

相关笔记

点击可直达,基本是我自己总结的书中的重点(我觉得),当然一些太高深我理解不了的东西也跳过了,比如 JVM 的源码,C++、汇编、编译原理相关的。

而 Java 语言基础这里基本不涉及,大多数都是内建 API 和语法之类的东西,有个两三年学习经验的基本都比较熟的,不同语言之间差距也不大,复盘可参考笔记『Java基础复习计划』和我博客里搜索『Java基础』关键字,配合下面 JVM 等相关知识,会有更深入的理解。

由于目前 Java8 已经进入大众阶段,也不再单独介绍相关特性,复盘还是参考我的笔记和博客亦或者《Java8实战》这本书,之前写过相关笔记。

  • 深入理解JVM(一)
    内存区域划分、GC 前置基础知识、JDK7 之前的内置 GC 解析。
  • 深入理解JVM(二)
    类文件结构、类加载过程
  • 深入理解JVM(补全)
    类文件相关补充、常量池、字节码指令、JIT 优化、并发与锁等
  • 一入Java深似海
    总结自小马哥的课程,对 Java 基础的深入探讨,另一种不同的角度去看待 Java。
  • Java11 Features
    Java 8 - 11 新特性总结
  • Java并发编程
    《Java并发编程的艺术》笔记
  • 深入JVM第三版补充(未完成)
  • 重构的艺术
    教你如何优雅的优化你写的代码,除了《重构》另外一本比较老的书没事也可以看看《代码整洁之道》

主要还是侧重 JVM、JUC、Java 基础这些东西,上面的笔记都挺长的,平均每一篇也得至少 1w+ 字,我觉得可都是精华。

JVM知识点

算是提纲吧,看着这个能说出来就不错了,忘记了就去相关笔记里翻吧。

  • 运行时数据区域划分与职责
    方法区、程序计数器、虚拟机栈、本地方法栈、堆;HotSpot 的实现。
    永久代与直接内存(元空间)
  • 对象访问定位
    句柄、直接指针
  • GC基础
    判断对象死活:引用计数(循环引用)、可达性分析、GCRoots;
    引用:强软弱虚;拓展之 ThreadLocal、直接引用;
    方法区回收;
    HotSpot 实现:枚举根节点 STW、安全点(抢先式中断、主动式中断)、安全区域;
    MinorGC、MajorGC/FullGC、动态年龄;
  • GC方案
    分代收集、标记清除、复制算法(担保机制)、标记整理;
    收集器:Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS(标记清除、低停顿)、G1;
    新收集器:Epsilon、ZGC、Shenandoah
  • JDK提供的分析工具
    经典:jps、jinfo、jstat、jstack、jconsole、jmap、VisualVM;
    新增:JFR、JMC、jshell
  • 类文件
    8 字节为单位二进制流、魔数、常量池(u2 自定义大小,包含字面量[表类型]和符号引用)、访问标志、字段表(字段重载)、方法表(重载)、属性表(严格顺序,可定制,其他表引用,32 位 solt 复用,u4/u2 方法长度 Code)、字节码指令(一个字节,非填充对齐,精简 int)
  • JVM 加载机制
    加载、连接(验证、准备、解析)、初始化、使用、卸载;
    零值、init/cinit、符号引用、直接引用、对象创建;
    类加载器:双亲委派模型、Bootstrap ClassLoader、Extension ClassLoader、Application ClassLoader、破坏(模块化与动态性、OSGi、JDBC、SPI、JNDI)
  • 字节码执行引擎
    基于栈(可移植,紧凑、实现简单、速度慢)、基于寄存器、32 bit solt(64 位的原子性问题)、动态连接、虚方法、非虚方法、动态分派(重写覆盖)、静态分派(多态);
    重叠操作数栈复用;
  • 编译器(早期)优化
    词法分析、语法分析(AST)、语法糖、注解处理器(Lombok 生成)、语义分析与字节码生成、自动拆箱、循环遍历(迭代器);
    方案:常量折叠、final 校验、解语法糖、字节码提升/生成(字符串拼接 SB)、条件编译、泛型擦除;
    (动态)提前编译(AOT):JDKJaotc、GCJ 等;以及 Android 的 ART(蹂躏 Dalvik)
  • 运行时(晚期)优化
    解释器+编译器混合模式、逃生门(逆优化)、Client Compiler(c1)、Server Compiler(c2)、分层编译(3 层)、JIT 基于方法;
    热点代码:方法(方法调用计数器)、循环(回边计数器,跑分)、基于采样热点探测(除前两种的其他)、基于计数热点探测、热度衰减、栈上替换(OSR)编译;
    c1:简单的三段式编译,速度快,优化例如:方法内联、消除访问冗余、复写传播、无用代码消除。
    c2:JIT + 监控,激进优化+逃生门,公共子表达式消除、数组边界检查消除、方法内联、逃逸分析(方法、线程逃逸,栈上分配、同步消除、标量替换)
  • 锁优化
    适应性自旋、锁消除、锁粗化、轻量级锁、偏向锁、锁升级(锁膨胀)

在《深入理解JVM》中也提到过一些 JUC 的知识,不过仅仅是入门,这里就不列了放到 JUC 条目中。


选择 GC 的指导原则:

  • 如果应⽤属于⼩规模数据应⽤(内存资源⼤概在 100 MB 左右)的话,那么串⾏收集器是⼀种不错的选择(-XX:+UseSerialGC)
  • 如果应⽤运⾏在单处理器并对停顿时间不敏感的话,那么它可以考虑串⾏收集器(XX:+UseSerialGC)
  • 如果应⽤属于性能敏感但停顿时间要求不⾼(如停顿⼀秒以上)的话,那么它可以选择并⾏收集 器(-XX:+UseParallelGC)
  • 如果应⽤认为响应时间⽐吞吐量和停顿时间更为重要的话,那么它可以考虑 CMS 或 G1 收集器

当应⽤在单处理器中运⾏时,Parallel Collector 不会⽐ Serial Collector 表现更好,因为并⾏ 执⾏反⽽需要额外的开销(如同步和线程切换等)

当应⽤在双处理器中运⾏时,即使 Heap 达到中型或⼤型的空间,Serial Collector 可能是最 合适的选择。

Parallel Collector ⽬标调整:

  • 最⼤垃圾收集停顿时间(Pause Times),默认无限制
  • 吞吐量(Throughput),决定于垃圾收集与其他应⽤执⾏时间的占⽐ 通过 JVM 参数 -XX:GCTimeRatio=<N> 调整 GC 时间与⾮ GC 时间的⽐重,GC 停顿时间等于 1 / N+1 N 默认值为 99,意味着 GC 时间占 1/100 的应⽤执⾏时间
  • 内存⾜迹(Footprint),指定各空间的大小。

JVM 默认的优先级顺序就是如上,Parallel Collector 每次垃圾收集过后,收集器将会保存并更新相关的统计信息,如平均的停顿时间。

Java基础

这里暂时先说一下比较容易忽视的知识点或者骚操作,那些面试常客,基本的就略过了。

  • 语言基础
    Java 访问修饰符是否四种?(JDK9 前后)、异常打印建议限制堆栈的深度;
    Java 是否是纯面向对象的?(原生类型)
    String 是否是不可变?(反射)、评价 Clone 方法(设计缺陷)、集合的线程安全(View);
    可以在 final 修饰类中定义抽象方法?(枚举、字节码提升);
    取余转为位运算(限制条件)、函数式编程、ClassLoader 加载(异常)、GC选择
  • 集合框架
    ConcurrentHashMap 或者说线程安全的 Map,为什么不允许 null 元素?(消歧义);
    Set、List、Map、Deque、Navigable*、Array/Linked/Tree;
    单例扩展:Collections.singleton*、空集合、转换集合接口、列举集合接口(of);
    集合包装(Collections):只读(unmodifiable)、同步(synchronized)、类型安全(checked,避免泛型擦除影响);
    特殊集合:优先级队列 PriorityQueue,枚举 Set: EnumSet;
    覆盖 equals 是否要覆盖 hashcode(建议),反之呢(必须),集合的比较重复逻辑(hashcode && (== || equals)
    鉴定 Map:IdentityHashMap(覆盖了 hashcode)MethodHandle;
    是否有必要覆盖 POJO 的 hashcode 和 eq?(用于 map、比较、排序建议覆盖,默认的递归层次深);
    自带排序:插入(7-)、快排(7+)、Tim排序(对象类型,更多的数量)
  • 并发基础
    ReentrantLock、ReentrantReadWriteLock、StampedLock(读多写少,读写锁升级版);
    线程池(默认的『无限』等待队列也不是很要紧,Tomcat、Nginx 这种会挡掉大部分);
    CountDownLatch、CyclicBarrier、Semaphore 、ThreadPoolExecutor 和 ScheduledExecutorService;
    并发集合:CopyOnWrite、ConcurrentSkipList、ConcurrentHashMap、BlockingQueue、Fork/Join、CompletableFuture、Flow(JDK9)、大小计算(并发集合中 size 一般是需要计算的)、InterruptedException;
    其他参考并发编程的列举
  • Java元编程
    JavaBeans(参考 Spring 的 ApplicationContextEvent)、Introspection、APT(Lombok、META-INF)
  • I/O
    NIO2、Fluent API(Builder API、Chain API)、try-with-resources(AutoCloseable);
    NIO:Buffers(0 <= mark <= position <= limit <= capacity)、Channels、Selectors、flip、rewind、Channels;
    其他:压缩(compact)、标记(mark,mark 设置为 position)、复制(duplicate)等
  • 其他
    ListIterator、快速失败(fail-fast)、失败安全(fail-safe)、user.dir、-XX:+PrintFlagsFinal

并发编程

这里提一句,美团技术团队的博客写的不错,个人比较推崇的 Java 国内圈俩神仙:美团技术团队和阿里中间件团队。

  • 处理器实现原子操作
    锁缓存、锁总线、Java 中 CAS 的缺点
  • 再谈Volatile
    缓存一致性协议,总线嗅探、缓存行对齐(JIT 无效化)、JVM 通过 lock 指令实现
  • 再谈Synchronized
    偏向锁获得和撤销、轻量级锁及膨胀、优缺点与使用场景
  • JMM
    解决主要矛盾(如何通讯、如何同步)、解决方案(共享内存和消息传递)、抽象概念;
    三种重排、内存屏障、happens-before 规则、顺序一致性、final 域(static、Synchronized)
  • AQS
    等待/通知经典范式(唤醒要继续判断)、等待超时模式、Lock 接口;
    AQS 使用方式、可重写方法、模版方法(三类)、同步队列、独占式、共享式、何时阻塞、读写锁;
    LockSupport 工具类、Condition 接口、等待队列(多对一)
  • JUC
    ConcurrentHashMap 原理(Java8 前后)、ConcurrentLinkedQueue(HOPS 优化更新频率)、长度计算;
    线程池、FutureTask

JVM性能监控与调优

我们并不能保证写的代码都是安全、高效的,尤其是时间紧的情况下,很多时候生产环境下跑才会发现问题,这时候如果有服务器权限并且我们有能力找出问题并解决,那么也是一个非常棒的技能。
最常见的就是 GC (内存泄漏)和线程(死锁、死循环)相关引起的问题。

TBD

临时参考博客的这篇文章

喜欢就请我吃包辣条吧!

评论框加载失败,无法访问 Disqus

你可能需要魔法上网~~