java核心技术
前段时间在极客时间上购买了杨晓峰老师的《java核心技术36讲》,趁着这段时间有空,对相关知识点做了一个整体的大纲,也对自己所掌握的java基础进行了一个复习和梳理,若想深入学习,可以购买这个专栏,也可以对着该知识点查阅相关资料,源码等自学。---- kayfen
文末附专栏链接
Java核心技术36讲知识点总结大纲
1 Java平台的理解
Java的特性,解释运行和编译运行
2 Exception 和 ERROR 有什么区别
- 理解Java的异常体系的设计,
throwable
,Exception
,Error
的关系 - 理解
ClassnotfoundException
与NoClassDefFoundError
的区别 - 遵循
Throw early, catch late
原则
3 final、finally、finalize 有什么不同
从安全、性能、垃圾收集方面考虑
4 强引用、软引用、弱引用、幻象引用有什么区别
对象的可达性状态:强引用 -> 软引用 -> 弱引用 -(finalize)->幻想引用
5 String、StringBuffer、stringbuilder有什么区别
- 字符串的设计与实现考量
- 字符串缓存 intern()方法,由永久代移到堆中。
- String 的演化,Java 9 中底层把 char 数组换成了 byte 数组,占用更少的空间
- getBytes()方法指定字符编码
6 动态代理是基于什么原理
- 反射原理
- 动态代理分类:JDK动态代理原理,cglib动态代理原理
- 优缺点,适用场景
7 int和integer有什么区别
- 基本类型和包装类型
- 包装类型的缓存
- 适应场景,性能影响
8 对比vector、ArrayList、LinkedList有何区别
- Collection 各种类的实现原理,使用场景
- List 的各种实现,Set 的各种实现,Queue的各种实现
- 理解Java提供的各种排序算法 collections.sort() arrays.sort()
9 对比Hashtable、HashMap、TreeMap有什么不同
- HashMap 实现原理,源码分析
- Java 8 HashMap 中的树化
- 容量和负载因子
- 解决哈希冲突的方法
10 如何保证集合是线程安全的? ConcurrentHashMap如何实现高效地线程安全
- HashTable 低效的加锁方式
- Collections 提供的同步包装器
- ConcurrentHashMap 的设计原理:
早期(Java 7)实现原理
- 分离锁 segment 对数组进行分段锁定,基于 ReetrantLock
- HashEntry内部使用 volatile 保证可见性
- 一个 Segment 可以对应多个桶,先定位到Segment 再进行二次哈希定位具体链表
- size() 方法获取大小时会进行2次重试,不保证一定准确
Java 8 和之后版本 ConcurrentHashMap 变化:
- 总体结构类似于 HashMap,锁的粒度更细
- 初始化利用volatile的
sizeCtl
检测是否发生竞争,若竞争则等待,然后CAS初始化 - 使用 CAS 操作进行无锁并发操作,key哈希得到桶的位置,为空进行CAS加新节点,否则使用
synchronized
加锁,链表达到数量之后转换红黑树 - size() 方法利用 LongAdd 进行累计
11 Java提供了哪些IO方式? NIO如何实现多路复用
- 传统的IO类库结构
- NIO 的基本组成和多路复用模型,Buffer,Channel,Selector
- socket IO 中 传统实现方式与 NIO 的区别
- NIO 2 的基本组成
- 区分同步和异步,阻塞和非阻塞
12 Java有几种文件拷贝方式?哪一种最高效
- 使用 java.io 包下的XXXStream 拷贝 和 使用 NIO 中的FileChannel的 transferTo()
- 理解用户态和内核态
- Files.copy 标准库的底层使用的还是用户态的拷贝
- NIO 中 Direct Buffer 堆外内存和垃圾收集(只有FullGC 时收集),使用场景
- 高效文件拷贝的原则:
- 使用缓存,减少IO次数
- transferTo 等机制,减少上下文切换和额外IO
- 尽量减少不必要的转换,编解码,对象序列化之类
13 谈谈接口和抽象类有什么区别
- 接口和抽象类的设计原则
- 面向对象基本要素:抽象,封装,继承,多态
- 面向对象的S.O.L.I.D原则:
- 单一职责
- 开关原则
- 里氏替换
- 迪米特法则
- 接口分离
- 依赖反转
14 谈谈你知道的设计模式
设计模式分类:
-
创建型模式—对对象创建过程的各种问题和解决方案的总结:
工厂模式、单例模式、构建器模式、原型模式
-
结构型模式—针对软件设计结构的总结,关注于类、对象继承、组合方式的实践:
桥接模式、适配器模式、装饰者模式、代理模式、组合模式、外观模式、享元模式等
-
行为型模式—从类或对象之间交互、职责划分等角度总结的模式:
通过实例学习和理解设计模式
Spring 中常见的设计模式:
- BeanFactory 和 APPlication 应用工厂模式
- Bean 的创建过程中,提供了单例和原型模式
- AOP 中的代理模式,装饰器模式,适配器模式
- 各种事件监听器,观察者模式
- 类似JdbcTemplate 的模板模式
15 synchronized 和 ReentrantLock 有什么区别
- 理解线程安全,保证线程安全有哪些方案
- 理解synchronized 和 ReentrantLock的机制和基本使用
- 线程安全的特性:原子性,可见性,有序性
- ReentrantLock的特点:公平锁,可重入锁,手动释放,超时等待,响应中断等
- Condition 的应用:Arrayblockingqueue 源码分析 lock 和 condition的作用
16 synchronized底层如何实现?什么是锁的升级、降级
- synchronized 代码块由 monitorenter/monitorexit 指令实现,Monitor对象是同步的基本单元
- Java 6之后 Monitor 的实现三种不同的锁:偏斜锁(BiasedLocking)、轻量级锁和重量级锁。升级降级就是三种不同锁的转换
- 没有竞争时使用偏向锁,JVM利用CAS在对象头的Markword设置当前线程ID
- 当有线程竞争时,需要撤销revoke偏向锁,利用CAS获取锁,成功则用轻量级锁,失败升级为重量级锁
- 不同的锁类型:
- 读写锁,StampedLock
17 一个线程两次调用start()方法会出现什么情况
-
理解线程的生命周期状态:java.lang.Thread.State:
- NEW
- RUNNABLE
- BLOCKED :阻塞,线程被挂起,无法进入临界区
- WaiTING :进入临界区后,发现某条件未达到而等待
- TIMED_WAIT :进入临界区后,基于超时的等待
- TERMINATED
-
线程是什么,Java底层的实现方式:
操作系统调度的最小单元,Java线程映射到OS内核线程
-
线程状态的切换
18 什么情况下Java程序会产生死锁?如何定位、修复
-
写一个死锁程序
-
诊断死锁的工具:
- jstack
- API:重量级操作
ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
Q:分布式环境可以用API实现吗
19 Java并发包提供了哪些并发工具类
-
java.util.concurrent 包下各类基本分类,使用
把握主要的组成部分:
- 各种同步结构
- countdownlatch 无法重用,countDown/await ,基于事件
- CyclicBarrier 可以重用,所有线程await() 之后自动重置,基于线程
- Semaphore
- Phase 与 CountDownLatch 类似,允许线程动态注册
- 各种线程安全容器
- 各种并发队列的实现和场景
- Executor框架
-
典型使用场景
车站出租车每次装5个人才能出发,再放入5个人进入
-
并发容器
20 并发包中的ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别
ArrayBlockingQueue
: 有界队列,一把锁,注意 add, offer , put 区别
SynchronousQueue
: 容量为0,每个操作都要等待
LinkedBlockingQueue
: 没有设置容量时为无界队列,头尾2把锁
ConcurrentLinkedQueue
: 基于CAS无锁的并发队列,性能更好,可以提供更高吞吐量
21 Java并发类库提供的线程池有哪几种? 分别有什么特点
-
Executors
工具类,ThreadPoolExecutor
线程池核心类 -
Executors 提供的线程池:
- newcachedThreadPool():
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
可根据实际情况调正线程池大小,需要注意的是线程数没有限制,空闲的线程缓存60秒
- newFixedThreadPool(int nThreads)
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
创建固定大小的线程池,工作队列使用
LinkedBlockingQueue
,使用时注意任务的堆积影响- newSingleThreadExecutor()
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
大小为1的线程池,同样要注意等待任务的堆积影响
一般建议使用 ThreadPoolExecutor
创建语义明确的线程池
22 AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?
- AtomicXXX 的实现原理:CAS原理
- CAS 有什么问题:
- ABA问题,解决方案:版本控制:AtomicStampedReference
- 自旋次数(CAS的设计前提是竞争时短暂的)
- 如果要使用CAS操作,可以使用 AtomicLongfieldUpdater 包装自己的数据
- 理解
AQS(AbstractQueuedSynchronizer)
的原理,简单拆分:- 表征状态的 volatile变量:state
- 一个FIFO 的等待线程队列,处理线程竞争和等待
- 各种基于CAS的基础操作方法,和等待实现的 tryAcquire 方法和 tryRelease 方法
- 以
ReentrantLock
为例理解 AQS 作为基础实现的作用
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
理解 tryAcquire 和 acquireQueued 方法的实现
23 请介绍类加载过程,什么是双亲委派模型
- Java 的类加载过程主要三个步骤:加载、链接(验证、准备、解析)、初始化
- 理解JVM各阶段做了什么工作
- 类加载器与双亲委派模型
- Java 9 中类加载器发生了哪些变化
- 有方法可以降低类加载开销吗 : AOT、AppCDS
24 有哪些方法可以在运行时动态生成一个Java类
25 谈谈JVM内存区域的划分,哪些区域可能发生outofmemoryError
- 程序计数器
- Java虚拟机栈
- 堆
- 方法区
- 运行时常量池
- 本地方法栈
注意JDK版本,JDK 7前还有把方法区
称为永久代
,之后由元数据区
取代,而字符串缓存和静态变量并没有转移到元数据区,是直接分配在了堆上
- 常见 OOM 分析
26 如何监控和诊断JVM堆内和堆外内存使用
细化对各部分内存区域的理解,堆内结构的理解,参数调整
参数调整:
- 最大堆体积 -Xmx value
- 初始化最小堆体积 -Xms value
- 老年代和新生代的比例 -XX:NewRatio=value
- 新生代大小比例 -XX:SurviorRatio=value
堆外内存
27 Java常见的垃圾收集器有哪些
- 主流 oracle JDK 的GC:
- Serial GC :采用标记-整理(Mark-Compact)算法
- ParNew GC : Serial GC的多线程实现
- CMS (Concurrent Mark sweep) GC : 基于标记-清除(Mark-Sweep)算法,存在内存碎片问题,设计目标是减少停顿
- Parrallel GC : 吞吐量优先的GC, JDK8 等为server 模式默认GC,新生代老年代并行
- G1 GC : 兼顾吞吐量和停顿时间,JDK 9后默认GC
- 如何判断一个对象是否可以回收?引用计数法和可达性分析
- 常见垃圾收集算法:
- 复制算法
- 标记-清除
- 标记-整理
- 垃圾收集的基本过程理解
28 谈谈你的GC调优思路
-
明确GC 调优的目的:性能角度(内存占用footprint、延时latency、吞吐量throughput),其他方面
-
一般调优思路:
- 明确需求和问题,确定目标
- 掌握JVM,GC的状态,是否有GC调优的必要
- 应用的特征和 GC的类型是否符合
- 分析确定需要调正的参数或软硬件
- 验证目标是否达到
-
G1 GC 的内部结构和主要机制
内部划分为同等大小的
region
(数值是在 1M 到 32M 字节之间的一个 2 的幂值数),年代成为逻辑概念,增加了Humongous
,G1会将超过 region 50%大小的对象归类为Humongous
对象,逻辑上属于老年代。- 新生代,G1 采用并行的复制算法,会发生 STW暂停
- 老年代,大部分情况为并发标记,整理发生在新生代GC时捎带进行,而且是增量进行
查询有关资料学习
29 Java内存模型中的happen-before是什么
-
Java (JMM)内存模型的理解
-
先行发生原则(Happen-before) 是Java内存模型中保证多线程操作可见性的机制
-
理解 JMM 试图解决什么问题:
-
JMM内部实现依赖于
内存屏障
,通过禁止某些重排序的方式,提供内存可见性保证。 -
线程安全的原子性,可见性,有序性的理解,同时理解(sychronized,volatile的原理)
30 Java程序运行在Docker等容器环境有哪些新问题
(由于本人在docker下使用java比较少,以下只摘录原专栏的主要点)
- 早期 JDK 在Docker 环境下容易出现的基础问题:
- 容器对计算资源的管理方式是全新的,Docker通过CCroup实现
- 解决方案:
- 根据容器设置好JVM的各种参数,包括CPU资源
- 升级到新的JDK 9 ,10
31 你了解Java应用开发中的注入攻击吗
注入攻击的基本特征是程序允许攻击者将不可信的动态内容注入到程序中,并将其执行。
常见注入攻击(Java相关):
32 如何写出安全的java代码
从Java语言的角度理解常见的攻击,如哈希碰撞等消耗资源的操作
从设计,开发,测试,部署等不同阶段考虑有哪些安全的策略
33 后台服务出现明显“变慢”,谈谈你的诊断思路
- 服务器变慢的定义,突然变慢还是长时间,是否重现,“慢”的定义
- 理清问题的症状,定位原因:
- 错误日志
- 系统资源等情况的检查
- 监控Java服务自身,GC日志是否异常
- 业界最广泛的性能分析方法论:
- 自上而下。从应用顶层逐步深入到具体模块
- 自下而上。从类似CPU这种底层往上分析
- 首先排除功能性错误,然后使用典型的自上而下分析:
- 系统层面关注点:CPU,内存,IO(top,free,iOStat等命令)
- JVM层面,利用工具,JMC,JConsole,日志等
34 有人说“lambda能让Java程序慢30倍”,你怎么看
- 理解基准测试定义的范围和目标
- 微基准测试
- JMH的使用
35 JVM优化Java代码时都做了什么
这部分内容建议参考 《深入理解Java虚拟机》及相关资料学习
36 谈谈mysql支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景
- MySQL事务隔离级别:
- 读未提交
- 读已提交
- 可重复读
- 串行化
- 理解
悲观锁
和乐观锁
的出发点及使用
37 谈谈Spring Bean的生命周期和作用域
-
Spring Bean生命周期
-
初始化参考下图:
-
销毁:依次调用 DisposableBean 的 destroy 方法和 Bean 自身定制的destroy 方法
-
-
Spring Bean 的作用域:
-
Spring 的基础机制:控制反转(依赖注入),AOP及具体相关概念
38 对比Java标准NIO类库,你知道Netty是如何实现更高性能的吗
(Netty 还不太熟悉,以后补上总结)
Netty 在NIO 基础上进行了很多改进:
39 谈谈常用的分布式ID的设计方案?Snowflake是否受冬令时切换影响
-
分布式ID的定义,基本要求:
- 全局唯一,分布式系统中的唯一
- 有序性,通常要求是有序递增
-
业界通常做法:
-
Snowflake 中大都依赖于
System.currentTimeMills()
与夏/冬时令没有关系,不受影响 -
分布式ID除了唯一和有序还会有其他要求,如有意义(业务相关),高可用性,紧凑等
-
主流方案的优缺点分析
- 数据库自增方案的局限
- 时钟偏斜问题
- 等等
有的知识点只是一带而过,可以参考更多资料和购买专栏,我觉得对着该大纲进行自己深入学习也是一个不错的选择。
专栏链接:
https://time.geekbang.org/column/intro/82?code=IAMPy%2FqD3Mg2lpnKMAho6zjuewt%2FKEVD8gX%2FUCdV7Xk%3D
相关阅读
弱引用和软引用WeakReference,SoftReference,最简讲解
他讲的很好,但是我看了一下,有些地方讲的不是很清楚,导致我当时困惑了一会。这里简单加点内容。实际上,Car car = new Car(22000,"sil
下面是在网上找的几种反编译软件的安装以及使用:一、JD-JUI官网下载链接:http://jd.benow.ca/下载之后解压,点击“jd-gui.exe”运行:
局部聚合向量(Vector of Locally Aggregated Descriptors,VLAD)一种编码方法,广泛用于基于音频的人脸识别、动态场景识别、头部姿态分
前面我们提到用-XX作为前缀的参数列表在jvm中可能是不健壮的,SUN也不推荐使用,后续可能会在没有通知的情况下就直接取消了;但是由于
本系列博客汇总在这里:JavaWeb_CSS 汇总目录p 和 span_边框一、p 的边框样式二、所有 html 在布局上都遵守盒子模型三、p 的内边框