共计 23865 个字符,预计需要花费 60 分钟才能阅读完成。
面试
-
个别都是由浅到深去问, 思路是:
- 先考查根底是否过关, 因为基础知识决定了一个技术人员倒退的下限
- 再通过深度考查是否有技术激情和深度以及技术的广度
-
同时可能会提出一些质疑和挑战来考查候选人是否与有不同意见的人沟通
考查内容和形式
基础知识
- 技术上深度与广度兼顾
-
基础知识: 考查根底的时候个别都不会深刻地去问, 次要目标是考查知识面
-
计算机实践根底:
- 计算机网络
- 数据结构
- 计算机组成原理
- 计算机操作系统
-
JDK:
- 源码
- 汇合
- BIO 或者 NIO
- annotation 等
-
JVM:
- 内存模型
- 类加载原理
-
数据库:
- 索引
- 事务
- 死锁等
-
并发:
- 并发的优缺点
- 内存可见性 – volatile
- 锁
- 同步
- 线程池框架
-
网络:
- TCP
- HTTP
-
常见设计模式
深刻考查
-
-
深刻考查:
- 深刻考查不会像考查根底时八面玲珑, 而是会在某个点上深刻去聊
- 这个点能够是让候选人本人选一个点, 也可能面试官依据简历内容去选
- 次要目标是考查候选人对某个技术点的深刻把握水平
- 技术是相通的, 如果一个人能在某个技术点上达到很深刻的水平, 其余点上也不会有太大问题, 如果某个人在宣称很理解的技术点上都支支吾吾, 只知其一; 不知其二, 多半能够判断此人要么技术无限, 要么遇到问题不愿深刻考查
- 考查工程师的工程能力, 比方: 做过哪些项目? 遇到最难的问题是什么? 怎么解决的? 说说最有成就感的一项工作
-
深刻考查的技术点:
-
Java 框架:
- Spring源码的 AOP 和IOC
-
JDK:
- ConcurrentHashMap 如何进步并发度
- NIO 的原理, 包含零拷贝, 堆外内存以及优缺点
-
虚拟机:
- 包抵触, 类抵触的造成原理以及解方法, 能够引申到 JDK 9 的模块化设计
- TCCL 的存在价值
-
服务器:
- Tomcat 源码
- Netty 源码
-
数据结构:
- 数组
- 链表
- 树
- 图
- 排序
- 算法
-
分布式:
- 缓存利用
- 一致性哈希
- RPC 原理和设计 – 通信协议, 序列化形式, 超时机制等
- 负载平衡
- 分布式缓存架构设计
- 分布式音讯
- 音讯队列设计与应用
- 分布式环境下中间件部署
- 分布式事务
- paxos
-
中间件:
- MQ
- ES
-
数据库:
- 数据库性能优化 – 慢 SQL, 索引优化, 大事务, 内核参数调优
- MySQL 数据库底层原理
- 工作中遇到的数据库问题以及解决办法
- Redis
-
并发:
- 非阻塞锁 CAS
- 并发对编译器优化的影响
- 线程池调优
- 工作中遇到的并发问题以及解决办法
-
技术趋势:
- Docker
-
微服务
业务相干
-
- 做的我的项目所应用的技术栈以及其中的优缺点?
- 如果从零开始, 能不能从新将其实现?
- 以后零碎的应用方是谁? 用户量多大? 用户集中应用的工夫点?
- 零碎落下了哪些数据? 这些数据的应用方是谁? 零碎的依赖方是谁?
-
从技术, 产品, 业务的角度去画下相干的流程图
工作交接
-
和产品, 业务, 经营, 技术之间的工作交接:
- 晓得本人的职责边界
- 弄清楚哪些是本人须要做的
- 哪些是其余的人应该做的
-
交换起来不卑不亢
面试筹备
-
面试最好的筹备形式:
- 肯定是平时多多积攒
- 遇到问题不要回避
- 深刻去思考并解决
- 在解决一个个问题的过程中积攒解决问题的能力, 造成本人的常识体系
-
如何提前准备将本人平时积攒展示进去:
- 针对面试考查内容知识点思考答案以及扩大. 如果能晓得大部分, 就要更加深刻一部分. 这个过程次要是整顿本人的常识体系
- 回顾整顿简历和过往我的项目中的 ” 难点 ”,” 亮点 ”, 因为这是用来辨别候选人的重要的点. 面试肯定会问 ” 在我的项目中经验最大的技术难点是什么?” 整顿一下思路, 不至于在面试时因为工夫长远而回顾不起来细节影响面试成果
-
沟通过程要做到有理有据, 不卑不亢. 在技术问题上保持本人的主观和准则, 依据独特认可的事实进行逻辑判断得出观点
面试内容
Java 根底
-
private 润饰的办法能够通过反射拜访, 那么 private 意义是什么?
-
考查对 Java 设计的把握水平
- Java 的 private 修饰符并不是为了相对安全性设计的, 更多的是对用户惯例应用 Java 的一种束缚
- 从内部对对象进行惯例调用时, 能够清晰理解类构造
-
- Java 中如何利用反射获取一个类的字段?
- 常见的类加载
-
Java 类的初始化程序?
-
Java 类的初始化程序:
- 基类动态代码块, 基类动态成员变量(并列优先级, 依照代码中呈现的先后顺序执行, 并且只有第一次加载时执行)
- 派生类动态代码块, 派生类动态成员变量(并列优先级, 依照代码中呈现的先后顺序, 并且只有第一次加载时执行)
- 基类一般代码块, 基类一般成员变量(并列优先级, 依照代码中呈现的先后顺序执行)
- 基类构造函数
- 派生类一般代码块, 派生类一般成员变量(并列优先级, 依照代码中呈现的先后顺序执行)
- 派生类构造函数
-
-
局部变量应用前须要显式赋值, 否则编译通过不了, 为什么须要这么设计?
-
成员变量:
- 能够不经初始化, 在类的加载过程中的筹备阶段能够赋予默认值
- 赋值和取值拜访的先后顺序具备不确定性
- 成员变量能够在一个办法调用前赋值, 也能够在办法调用后进行赋值. 这是在运行时产生的, 编译器确定不了, 所有交给 JVM 来赋值
-
局部变量:
- 在应用之前须要显式赋予初始值
- 局部变量的赋值和拜访程序是确定的
-
这样设计是一种束缚, 尽最大可能缩小使用者犯错:
- 倘若局部变量能够应用默认值, 可能总会无意间遗记赋值, 进而导致不可预期的状况产生
-
- ArrayList,LinkList 的区别? 插入和查找哪个更快?
- ArrayList 的随机插入?
- LinkList 是单向链表还是双向链表?
- 单向链表如何实现一个栈?
- HashMap 的 put 操作底层是如何实现的?
- HashTable,ConcurrentHashMap 的区别? 为什么 ConcurrentHashMap 并发度更高?
- ConcurrentHashMap 中的 get 和 set 什么时候会加锁? 如果不加锁会产生什么问题? 什么时候是 CAS 操作?
-
HashMap 的原理, 在 Java 8 中做了哪些扭转?
-
从构造实现上来讲:
- HashMap 实现是数组 + 链表 + 红黑树(红黑树局部是 JDK 1.8 之后减少的)
- HashMap 最多容许一条记录的键为 null, 容许多条记录的值为 null
- HashMap 是非线程平安的
-
-
String 与 StringBuilder 的区别?
-
可变与不可变:
- String 不可变, 每一次执行 “+” 都会新生成一个新对象, 所以频繁扭转字符串的状况下不必 String, 以节俭内存
-
是否多线程平安:
- StringBuilder 并没有对办法进行加同步锁, 所以是非线程平安的.StringBuffer 和 String 都是线程平安的
-
-
Vector 和 Array 的区别?
- ArrayList在内存不够时默认扩大是 50%+1 个,Vector 默认是扩大 1 倍
- Vector 是属于线程安全级别的, 然而大多数状况下不应用 Vector, 因为线程平安须要更大的零碎开销
-
HashMap 和 HashTable 的区别?
- HashTable 继承 Dictionary 类,HashMap 继承 AbstrctMap 类
- HashTable 不容许空键值对, 而 HashMap 容许空键值对, 但最多只有一个空对象
- HashTable 同步, 而 HashMap 不同步, 效率上比 HashTable 要高
-
ConcurrentHashMap 和 HashTable 比拟, 两个线程并发拜访 Map 中同一条链, 一个线程在尾部删除, 一个线程在后面遍历查找. 为什么后面的线程还能正确的查找到前面被另一个线程删除的节点?
-
ConcurrentHashMap 交融了 HashTable 和 HashMap 二者的劣势:
- HashTable 是做了同步的, 是线程平安的, 而 HashMap 未思考同步, 所以 HashMap 在单线程状况下效率比拟高
- HashTable 在多线程的状况下, 同步操作能保障程序执行的正确性
- 然而 HashTable 是阻塞的, 每次同步执行的时候都要锁住整个构造
-
ConcurrentHashMap 正好解决了效率和阻塞问题:
- ConcurrentHashMap 容许多个批改操作并发进行, 技术的要害是应用了锁拆散, 即一个 Array 保留多个 Object, 应用这些对象的锁作为拆散锁,get 或者 put 的时候随机应用任意一个
- ConcurrentHashMap 应用了多个锁来管制对 Hash 表的不同局部进行的批改
-
从 JDK 1.6 开始, 在 HashEntry 构造中, 每次插入将新增加节点作为链的头节点, 这与 HashMap 实现雷同.
- 每次删除一个节点时, 会将删除节点之前的所有节点拷贝一份组成一个新的链, 而将以后节点的上一个节点的 next 指向以后节点的下一个节点. 从而在删除当前会有两条链存在
- 因而能够保障即便在同一条链中, 有一个线程在删除, 而另一个线程在遍历, 都能工作良好. 因为遍历的线程能持续应用原有的链
-
在 Java 8 中, 应用 volatile HashEntry 保留数据,table 元素作为锁. 从 Table 数组 + 单向链表又加上了红黑树
-
红黑树是一种特地的二叉查找树, 红黑树的个性:
- 节点为红或黑
- 根节点为黑
- 叶节点为黑
- 一节点为红, 则一节点为黑
- 一节点到其子孙节点所有门路上的黑节点数目雷同
-
-
-
ArrayList 和 LinkedList 的区别?
- ArrayList 底层的数据结构是数组, 反对随机拜访.LinkedList 的底层数据结构是链表, 不反对随机拜访
-
应用下表拜访一个元素:
- ArrayList的工夫复杂度是O(1)
- LinkedList的工夫复杂度是O(n). LinkedList 是双向链表
- HashMap 中 put()元素产生抵触, 为什么应用 LinkedList 拉链法解决而不必 ArrayList 解决? 产生抵触时 key 值不等, 新元素怎么样退出链表? 为什么这么设计?
-
Java 中的 Comparator 和 Comparable 有什么不同?
- Comparable 接口用于定义对象的天然程序, 是排序接口
-
Comparator 通常用于定义用户定制的程序, 是比拟接口
- 如果须要管制某个类的秩序, 而该类自身不反对排序, 即没有实现 Comparable 接口, 就能够建设一个 ” 该类的比拟器 ” 来进行排序
- Comparable 总是只有一个, 然而能够有多个 Comparator 来定义对象的程序
-
抽象类是什么? 与接口有什么区别? 为什么要应用抽象类?
- 抽象类是不容许被实例化的类, 一个类只能应用一次继承关系, 然而一个类能够实现多个接口
-
抽象类和接口所反映出的设计理念不同:
- 抽象类示意的是 “is – a”
- 接口示意的是 “like – a”
-
实现抽象类和接口的类必须实现其中的所有办法. 抽象类能够有非形象办法, 接口中则不能有实现办法, 然而在 Java 8 中容许接口中有动态默认办法
- 接口 中定义的变量默认是 public static final 型, 且必须给出初值, 所以实现类中不能从新定义, 也不能扭转这个值
- 抽象类 中定义的变量默认是 friendly 型, 这个变量的值能够在子类中从新定义, 也能够从新赋值
- 子类中实现父类中的形象办法时. 可见性能够大于等于父类中的
- 接口实现类类中的接口办法的可见性只能与接口中的雷同, 即为 public
- 应用抽象类是为了重用, 缩小编码量, 升高耦合性
-
Java 中的重载和重写?
- 重载和重写都是应用雷同的名称实现不同的性能, 然而重载是编译时流动, 重写是运行时流动
- 能够在同一个类中重载办法, 但只能在子类中重写办法, 重写必须要有继承
-
重载:
- 重载的时候, 办法名要一样, 然而参数类型和参数个数不一样, 返回值类型能够雷同也能够不同
- 无奈以返回型别作为重载函数的辨别规范
-
重写:
- 在子类中能够依据须要对从基类中继承的办法进行重写
- 重写的办法和被重写的办法必须具备雷同的办法名称, 参数列表和返回类型
- 重写办法不能应用比被重写办法更严格的拜访权限
-
Collection 和 Collections 的区别是什么?
- Collection< E > 是 Java 汇合框架中的根本接口
- Collections 是 Java 汇合框架提供的一个工具类, 其中蕴含了大量用于操作和返回汇合的静态方法
-
Java 中多态的实现原理?
- 多态指的是父类援用指向子类的对象, 调用办法时会调用子类的实现而不是父类的实现
- 多态的实现关键在于 动静绑定
-
Object 中定义了哪些办法?
- clone()
- equals()
- hashCode()
- toString()
- notify()
- notifyAll()
- wait()
- finalize()
- getClass()
-
Java 中的泛型和类型擦除?
- 泛型即参数化类型, 在创立汇合时, 指定汇合元素的类型, 此汇合只能传入该类型的参数
-
类型擦除:Java 编译器生成的字节码不包含泛型信息, 所以在编译时擦除
- 泛型用最顶级的父类替换
- 移除
-
JDK 1.8 引入的新个性?
- Lambda 表达式
- 容许像对象一样传递匿名函数 Stream API, 充分利用古代多核 CPU, 能够写出很简洁的代码
- Date 与 Time API, 有一个稳固简略的日期和工夫库可供使用
- 接口中能够有动态, 默认办法
- 反复注解, 能够将雷同的注解在同一类型上应用屡次
-
Java 中 public,private,protected 以及默认关键字的拜访范畴?
- protected 可在包内及包外子类拜访
- default 只能在同一包内拜访
- private 只能在同一个类中拜访
-
罕用的数据结构?
- 汇合
-
线性构造
- 数组
- 队列
- 链表
- 栈
- 树形构造
- 图状构造
-
Java 中的 TreeMap 是采纳什么树实现的?
Java 中的 TreeMap 是应用红黑树实现的
-
匿名外部类是什么? 如何拜访在匿名外部类里面定义的变量?
- 匿名外部类就是没有名字的外部类, 匿名外部类只能应用一次, 通常用来简化代码编写
- 匿名外部类只能拜访外部类的 final 变量
- 在 Java 8 中, 如果局部变量被匿名外部类拜访, 那么该局部变量相当于主动应用了 final 润饰
-
如何高效地创立一个线程平安的单例模式?
- 通过枚举
- 通过动态外部类
- 也能够通过双重查看创立单例模式, 然而这种单例模式是线程不平安的
-
poll()办法和 remove()办法的区别?
- poll()和 remove 都是从队列中取出一个元素
- poll()在获取元素失败时会返回空
- remove()在获取元素失败时会抛出异样
-
写一段代码在遍历 ArrayList 时移除一个元素?
-
应用迭代器
Iterator it = list.iterator(); while (it.hasNext()) {if (...) {it.remove(); } }
-
- 注解的原理
-
开源协定哪些?
- GPL: GNU General Public License,GNU 通用公共许可协定
- LGPL: GNU Lesser General Public License, GNU 宽通用公共许可协定
- BSD: Berkeley Software Distribution, 伯克利软件散发许可协定
- MIT: Massachusetts Institute of Technology
- Apache: Apache Licence, Apache 许可协定
- MPL: Mozilla Public Licence, Mozilla 公共许可协定
线程
-
线程同步与阻塞关系? 同步肯定阻塞吗? 阻塞肯定同步吗?
- 线程同步与否和阻塞非阻塞没有关系
- 同步是一个过程, 阻塞是线程的一种状态
- 多个线程操作共享变量时会呈现竞争
- 须要应用同步来避免两个以上的线程同时进入临界区内, 在这个过程中, 后进入临界区的线程将阻塞, 期待先进入的线程走出临界区
-
同步和异步有什么区别?
- 同步和异步最大的区别是: 一个须要期待, 一个不须要期待
-
同步能够避免出现死锁, 读脏数据的产生, 个别共享某一资源的时候应用
- 如果每个人都有批改权限, 同时批改一个文件, 有可能使一个人读取另一个人曾经删除的内容, 就会出错
- 同步就会依照程序来批改
-
线程池?
- 线程池的作用是依据零碎本身的状况, 无效的限度执行线程的数量, 使得运行成果达到最佳
-
线程池次要执行的是:
- 管制执行线程的数量
- 超出数量的线程排队等待
- 期待有工作执行结束
- 再从队列中最后面取出工作执行
-
如何调用 wait()办法? 应用 if 块还是循环? 为什么?
-
wait()办法应该在循环中调用:
- 因为当线程获取到 CPU 开始执行的时候, 其余条件可能还没有满足
- 所以在解决前, 循环检测条件是否满足更好
- wait(),notify()和 notifyAll()办法是 java.lang.Object 类为线程提供的用于实现线程间通信的同步控制的期待和唤醒办法
-
-
实现线程的几种办法?
-
实现线程的办法:
- 继承 Thread 类, 重写 run 函数
- 实现 Runnable 接口, 重写 run 函数
- 实现 Callable 接口, 重写 call 函数
-
-
什么是多线程环境下的伪共享 – false sharing?
-
伪共享是多线程零碎 (这个零碎的每隔处理器都有本人的部分缓存) 中一个普遍存在的性能问题
- 缓存零碎中是以缓存行 (cache line) 为单位存储的
- 缓存行是 2 的整数幂个间断字节, 个别为 32 – 256 字节
- 最常见的缓存行是 64 个字节
- 当多线程批改互相独立的变量时, 如果这些变量共享同一个缓存行, 就会影响彼此的性能, 这就是伪共享
-
- 线程的状态?
-
concurrent 包上面, 都用过哪些包?
- java.util.concurrent
- java.util.concurrent.atomic
- java.util.concurrent.lock
-
ReadWriteLock 读写之间互斥吗?
-
ReadWriteRock 读写锁的应用场景:
- 读 – 读
- 读 – 写
- 写 – 写
- 除了 读 – 读 之间是共享的, 其余都是互斥的
-
-
怎么实现互斥锁和同步锁
- 考查对 AQS, CAS 的把握水平
-
Java 并发编程中的辅助类?
- Semaphore
- CountDownLatch
- CyclicBarrier
- Exchanger
- CountDownLatch 和 CyclicBarrier 之间的区别?
-
ReadWriteLock 之间互斥吗?
-
ReadWriteLock 读写锁的应用场景:
- 读, 读
- 读, 写
- 写, 写
- 除了读和读之间是共享的, 其余都是互斥的
这样之后会探讨怎么实现互斥锁和同步锁的, 理解对 AQS,CAS 的把握水平, 技术学习深度
-
-
Semaphore 拿到执行权的线程之间是否互斥?
- Semaphore 拿到执行权的线程之间是互斥的
- Semaphore, CountDownLatch, CyclicBarrier, Exchanger是 Java 并发编程中的 4 个辅助类, 理解 CountDownLatch 和 CyclicBarrier 之间的区别
- Semaphore 可能有多把锁, 能够容许多个线程同时领有执行权, 这些有执行权的线程如果并发拜访同一对象, 会产生线程平安问题
-
Semaphore:
- 能够有多把锁, 容许多个线程同时领有执行权
- 这些有执行权的线程如果并发拜访同一对象, 会产生线程平安问题
- 线程是怎么依照程序执行的?
- 线程执行过程中遇到异样会产生什么, 怎么解决?
-
写出一个单例模式?
- 单例模式是最常遇到的设计模式之一, 考查对常常碰到的问题的了解的深度
-
单例一共有 5 种实现形式:
- 饿汉
- 懒汉
- 动态外部类
- 双检锁
-
- 枚举
-
要是写了简略的懒汉式可能会问: 要是多线程状况下怎么保障线程平安呢?
- 应用双检锁能够保障线程平安.
-
为什么要两次校验? 光是双检锁还会有什么问题?
- 对象在定义的时候加上 volatile 关键字
- 引申探讨原子性和可见性,Java 内存模型, 类的加载过程
-
枚举形式, 动态外部类, 双检锁都能够实现单例模式. 双检锁的单例模式:
public Class Singleton {private Singleton() { } private volatile static Singleton instance; public static Singleton getInstance() {if (null == instance) {synchronized (Singleton.class) {if (null == instance) {instance = new Singleton(); } } } return instance; } }
- 双检锁写一个单例模式, 为什么要应用 volatile 润饰对象?
- Object object = new Object(); 这里的 object 为 null 吗? 为什么?
- Object object = new Object(); 初始化的程序是什么? 在 JVM 各个区域做了什么?
-
什么状况下会产生死锁? 写一个死锁?
- 死锁的四个条件:
-
示例: 定义两个 ArrayList, 都加上锁 A,B. 线程 1,2. 线程 1 获取到锁 A, 申请锁 B. 线程 2 获取到锁 B, 申请锁 A. 在期待对方开释锁的过程中都不会让出已取得的锁
public class DeadLock {public static void main(String[] args) {final List<Integer> list1 = Arrays.asList(1, 2, 3); final List<Integer> list2 = Arrays.asList(4, 5 ,6); new Thread(new Runnable() { @Override public void run() {synchronized (list1) {for (Integer i : list1) {System.out.println(i); } try {Thread.sleep(1000); } catch (InterruptedException e) {e.printStackTrace(); } synchronized (list2) {for (Integer i : list2) {System.out.println(i); } } } } }).start(); new Thread(new Runnable() { @Override public void run() {synchronized (list2) {for (Integer i : list2) {System.out.println(i); } try {Thread.sleep(1000); } catch (InterruptedException e) {e.printStackTrace(); } synchronized (list1) {for (Integer i : list1) {System.out.println(i); } } } } }).start();} }
-
String a = “ab”; String b = “a” + “b”; a == b; 是否相等, 为什么?
- 相等
- new 一个对象赋给变量
- 这行表达式创立了几个对象
-
int a = 1; 是原子性操作吗?
- 是
-
能够应用 for 循环间接删除 ArrayList 的特定元素吗? 可能会呈现什么问题? 怎么解决?
-
不能够应用 for 循环间接删除 ArrayList 中的特定元素:
- 不同的 for 循环会产生不同的异样
- 泛型 for 会抛出 ConcurrentModificationException
- 一般的 for 想要删除汇合中反复且间断的元素, 只能删除第一个
-
起因:
- JDK 中的 ArrayList 源码
-
ArrayList 中的 remove 有两个同名办法, 只是入参不同:
-
入参为 Object 的实现:
- 个别状况下程序的执行门路走到 else 门路下最终调用faseRemove() 办法, 会执行System.arraycopy() 办法, 导致删除元素时波及到数组元素的挪动
- 一般 for 循环, 在 遍历第一个合乎删除条件的字符串时将该元素从数组中删除, 并且将后一个元素即第二个元素挪动到以后地位, 导致下一次遍历时后一个字符串并没有遍历胜利, 所以无奈删除. 这种能够应用 倒序删除 的形式来防止
-
-
解决办法: 应用迭代器Iterator
List<String> list = new ArrayList(Arrays.asList("a", "b", "b", "c", "d")); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) {String element = iterator.next(); if ("b".equals(element)) {iterator.remove(); } }
-
-
新的工作提交到线程池, 线程池是怎么解决的?
- 第一步: 线程池判断外围线程池里的线程是否都在执行工作. 如果不是, 则创立一个新的工作线程来执行工作. 如果外围线程池里的线程都在执行工作, 则执行第二步
- 第二步: 线程池判断工作队列是否曾经满了. 如果工作队列没有满, 则将新提交的工作存储在这个工作队列中期待. 如果工作队列满了, 则执行第三步
- 第三步: 线程池判断线程池的线程是否都处于工作状态. 如果没有, 则创立一个新的工作线程来执行工作. 如果曾经满了, 则交给饱和策略来解决这个工作
-
AQS 和 CAS 原理?
-
形象队列同步器 AQS: AbstractQueuedSychronizer
- 如果说 java.util.concurrent 的根底是 CAS 的话, 那么 AQS 就是整个 Java 并发包的外围
- ReentrantLock, CountDownLatch, Semaphore 都用到了 AQS
-
AQS 实际上以双向队列的模式连贯所有的 Entry:
- ReentrantLock: 所有期待的线程都被放在一个 Entry 中并连成双向队列, 后面一个线程应用 ReentrantLock 好了, 则双向队列实际上的第一个 Entry 开始运行
- AQS 定义了对双向队列所有的操作, 并且只凋谢了 tryLock 和 tryRelease 办法给开发者应用. 开发者能够依据本人的实现重写 tryLock 和 tryRelease 办法来实现本人的并发性能
-
比拟并替换 CAS: Compare and Swap
-
假如有三个操作数:
- 内存之 V
- 旧的预期值 A
- 要批改的值 B
- 当且仅当预期值 A 和内存值 V 雷同时, 才会将内存值批改为 B 并返回 true. 否则什么都不做并返回 false.
- 整个比拟并替换的操作是一个原子操作
- CAS 必须要 volatile 变量配合, 这样能力保障每次拿到的变量是主内存中最新的响应值. 否则旧的预期值 A 对某条线程来说, 永远是一个不会变的值 A. 只有某次 CAS 操作失败, 则 CAS 操作永远不会胜利
-
CAS 高效地解决了原子操作的问题, 但依然存在三大问题:
- 循环工夫长开销很大
- 只能保障一个共享变量的原子操作
- ABA 问题
-
-
- AtomicLong 的底层实现原理?
- ReentrantLock 是可重入锁, 什么是可重入锁?
- CAS 底层是怎么样实现原子性的?
-
synchronized 底层实现原理?
-
synchronized(this)原理:
- 两条指令: monitorenter 和 monitorexit
- 同步办法: 从同步办法的反编译的后果中能够看出 – 办法的同步并没有通过指令 monitorenter 和 monitorexit 来实现, 绝对于一般办法, 在常量池中多了 ACC_SYNCHRONIZED 标识符
-
JVM 就是依据 ACC_SYNCHRONIZED 标识符来实现办法同步的:
- 当办法被调用时, 调用指令将会查看办法的 ACC_SYNCHRONIZED 拜访标记是否被设置
- 如果设置了, 执行线程将先获取 monitor, 获取胜利之后能力执行办法体, 办法执行完之后再开释 monitor
- 在办法执行期间, 其余任何线程都无奈再取得同一个 monitor 对象
-
- lock 和 synchronized 的区别?
- Java 对象头信息, 偏差锁, 轻量锁, 重量级锁及各自相互间的转化?
- 润饰类的锁和润饰办法的锁的区别?
-
volatile 作用, 指令重排相干?
- 了解 volatile 关键字的作用的前提是要了解 Java 的内存模型
-
volatile 关键字的作用次要有两点:
- 多线程次要围绕可见性和原子性两个个性开展. 应用 volatile 关键字润饰的变量, 保障了在多线程之间的可见性. 即每次读取到 volatile 变量, 肯定是最新的数据
- 底层代码的执行: Java 代码 -> 字节码 -> 依据字节码执行对应的 C /C++ 代码 -> C/C++ 代码被编译成汇编语言 -> 和硬件电路交互. 事实中, 为了获取更好的性能,JVM 可能会对指令进行重排序, 多线程下可能会呈现意想不到的问题. 应用 volatile 则会禁止对语义重排序, 不过也会肯定水平上升高代码的执行效率
- 从实际角度而言,volatile 的一个重要作用就是和 CAS 联合, 保障了原子性. 比方 AtomicInteger
Java 线程池
- 线程池的工作原理以及外围参数
- 线程池的结构参数?
- 如何中断一个线程, 具体实现? 正在 running 的线程可能被中断吗?
- 线程中的线程个数, 如何来设置? 计算性的个数是 CPU 的个数还是 CPU 个数的 2 倍?
- CPU 100% 怎么定位?
数据结构
-
B 树和 B + 树是解决什么样的问题的? 怎么演变过去的? 两者之间的区别是什么?
- B 树和 B + 树, 既考查 MySQL 索引的实现原理, 也考查数据结构根底
-
首先从二叉树说起:
- 因为会产生进化景象, 提出均衡二叉树
- 再提出怎么样让每一层放的节点多一些来缩小遍历高度, 引申出 m 叉树
- m 叉搜寻树同样会有进化景象, 引出 m 叉均衡树, 即 B 树
- 这个时候每个节点既放了 key 又放了 value. 怎么使每个节点放尽可能多的 key 值, 以缩小遍历高度也就是拜访磁盘的次数
- 能够将每个节点只放 key 值, 将 value 值放在叶子节点, 在叶子节点的 value 值减少指向相邻节点的指针, 这就是优化后的B+ 树
-
而后谈谈数据库索引生效的状况:
- 为什么给离散度低的字段, 比方性别建设索引是不可取的? 查问数据反而更慢
- 如果将离散度高的字段和离散度低的字段, 比方性别建设联结索引会怎么, 有什么须要留神的?
Spring
- 看过哪些框架的源码?
- 什么是 Spring 框架? Spring 框架有哪些模块?
- Spring 中应用了哪些设计模式?
- Spring 框架的益处?
- 什么是 IOC 管制反转?
- 什么是依赖注入以及原理?
- Spring 中 @Autowired 和 @Resource 的区别?
- BeanFactory 和 ApplicationContext 有什么区别?
- Spring Bean 的生命周期?
- Spring Bean 的作用域有哪些以及各种作用域之间有什么区别?
- Spring 框架中的单例 Beans 是线程平安的吗?
- BeanFactory 和 FactoryBean 的区别和利用场景?
- Spring 的代理如何实现?
- JDK 代理机制?
-
AOP 和 IOC 原理?
- AOP 和 IOC 是 Spring 的精髓局部
-
AOP:
- AOP 能够看作是对 OOP 的补充, 对代码进行横向扩大
- 通过代理模式实现. 代理模式有动态代理和动静代理.
- Spring 利用的是动静代理, 在程序运行过程中将加强代码织入源代码中
-
IOC: 管制反转
- 将对象的控制权交给 Spring 框架, 用户应用对象无需创立, 间接应用即可
- AOP 和 IOC 重点要理解设计思维
-
Spring 怎么解决循环依赖的问题
-
Spring 的循环依赖问题:
- 什么是循环依赖?
- 怎么检测出循环依赖?
- Spring 循环依赖有几种形式, 应用基于 setter 属性的循环依赖为什么不会呈现问题?
-
-
Bean 的生命周期?
-
dispatchServlet 怎么散发工作的?
- 1. 用户发送申请 -> DispatcherServlet: 前端控制器收到申请后本人不进行解决, 而是委托给其余解析器进行解决, 作为对立的拜访点, 进行全局的流程管制
- 2. DispatcherServlet -> HandlerMapping: HandlerMapping 将会把申请映射为 HandlerExecutionChain 对象.HandlerExecutionChain 蕴含一个 Hander 处理器, 多个 HandlerInterceptor 拦截器
- 3. DispatcherServlet -> HandlerAdapter: HandlerAdapter 将会将处理器包装为适配器, 从而反对多种类型的处理器
- 4. HandlerAdapter -> 处理器性能办法的调用: HandlerAdapter 将会依据适配的后果调用真正的处理器的性能解决办法, 实现性能解决, 并返回一个 ModelAndView 对象. ModelAndView 对象蕴含模型数据. 逻辑视图名
- 5. ModelAndView 的逻辑视图名 -> ViewResolver: ViewResolver 将逻辑的视图名解析为具体的 View
- 6. View -> 渲染: View 会依据传进来的 Model 模型数据进行渲染, 这里的 Model 是一个 Map 数据结构
- 7. 返回控制权给 DispatcherServlet, 由 DispatcherServlet 返回响应给用户
数据库
-
数据库中的范式有哪些?
- 第一范式: 数据库中的表的所有字段值都是不可分割的原子数据项
- 第二范式: 数据库表中的每一列都和主键相干, 而不能只和主键的某一部分相干
- 第三范式: 数据库表中每一列数据都和主键间接相干, 不能间接相干
- 范式是为了缩小数据冗余
-
MySQL 给离散度低的字段建设索引会呈现什么问题?
- 重复性强的字段, 不适宜增加索引
- MySQL 给离散度低的字段, 比方性别设置索引, 再以性别作为条件查问反而会更慢
-
一个表可能会波及两个数据结构:
- 数据表: 寄存表中的数据
- 索引
-
索引:
-
将一个或几个字段 (组合索引) 按法则排列起来, 再附加上该字段所在行数据的物理地址(位于表中)
- 比方有个字段是年龄, 如果须要选取某个年龄段的所有行, 那么个别状况下可能须要进行一次全表扫描
- 然而如果以这个年龄段建设一个索引, 那么索引会依照年龄值依据特定的数据结构建一个排列, 这样在索引中就能迅速定位, 不须要进行全表扫描
-
-
为什么性别不适宜建设索引呢?
- 因为拜访索引须要有额定的 IO 开销, 从索引中拿到的只是地址, 要想真正拜访到数据还是要对表进行一次 IO
- 如果要从表中的 100 万行数据中取几个数据, 那么利用索引迅速定位, 拜访索引的 IO 开销就能够忽略不计
- 如果要从标中的 100 万行数据取 50 万行数据, 再拜访 50 万次表, 加起来的开销并不会比对表进行一次残缺的扫描小
- 如果将性别字段设为聚焦索引, 那么必定能放慢大概一半该字段的查问速度
-
聚焦索引:
- 指的是表自身数据依照哪个字段的值来进行排序
- 聚焦索引不会付出额定 IO 开销
- 聚焦索引只能有一个
- 因而聚焦索引要用到搜寻最频繁的字段上
- 能够依据业务场景须要, 将性别和其余的字段建设联结索引. 比方工夫戳, 要将工夫戳字段放在性别后面
- MySQL 的最左匹配准则?
- MySQL 的隔离级别?
- B+,B 树的区别?
- MySQL 的常见优化和注意事项?
- 数据库慢查问优化思路
-
MySQL 中的 log 有哪些? 别离有什么作用?
- undo log:
- redo log:
- binlog:
- 数据库 ACID?
- 数据库事务的隔离级别?
- 数据库的分库分表?
- 分库分表的全局惟一 ID 如何实现?
-
数据库中的索引的构造? 什么状况下适宜建索引?
-
数据库中的索引的构造是一种排序的数据结构, 数据库的索引是通过 B 树和变形的 B + 树实现的
-
什么状况下不适宜建设索引:
- 对于在查问过程中很少应用或者参考的列
- 对于只有很少数据值的列
- 对于定义为 image,text 和bit数据类型的列
- 当批改性能远远大于检索性能时
-
-
依据零碎本身的环境状况, 无效限度线程数量, 使得运行成果达到最佳
- 线程次要是通过管制执行线程的数量, 超出数量的线程排队等待, 期待有工作执行结束, 再从队列最后面取出工作执行
-
-
MySQL 罕用优化?
- SQL 优化
- 表构造优化
- 索引优化
- 缓存参数优化
- Redis 的数据类型有哪些?
分布式
- CAP 实践?
-
写一个生产者消费者模式?
-
生产者消费者模式:
-
synchronized锁住一个LinkedList:
- 生产者: 只有队列不满, 生产后往里存
- 消费者: 只有队列不空, 生产后往外取
- 两者通过wait() 和notify() 进行协调
-
- 要思考怎么样提高效率
- 相熟音讯队列设计精要思维及应用
-
-
为什么要应用音讯队列 MQ?
- 异步解决: 绝对于传统的串行, 并行形式, 进步了零碎的吞吐量
- 利用解耦: 零碎间通过音讯通信, 不必关怀其余零碎的解决
- 流量削峰: 能够通过音讯队列长度管制申请量, 能够缓解短时间内高并发申请
- 日志解决: 解决大量日志传输
- 音讯通信: 音讯队列个别都内置了高效的通信机制, 因而能够用在纯的音讯通信. 比方实现点对点音讯队列, 聊天室等
-
如何保障音讯队列 MQ 的高可用?
- 将所有 Broker 和待调配的 Partition 排序
- 将第 i 个Partion调配到第 (i mod n) 个 Broker 上
- 将第 i 个Partion的第 j 个Replica调配到第 ((i+j) mod n) 个 Broker 上
-
MQ 有哪些常见问题? 如何解决这些问题?
-
音讯队列的程序问题
- 音讯有序指的是能够依照音讯的发送程序来生产
-
假设生产者产生了 2 条音讯:M1,M2. 假设 M1 发送到 S1,M2 发送到 S2. 如果要保障 M1 优先于 M2 被生产, 如何保障:
-
解决方案:
- 保障 生产者 – MQSever – 消费者 是一对一对一的关系
-
缺点:
- 并行度会成为零碎的瓶颈, 吞吐量不够
- 会呈现更多的异样解决问题: 只有消费者呈现问题, 就会导致整个流程梗塞, 不得不解决阻塞的问题
-
能够通过正当的设计或者将问题合成来躲避:
- 不关注乱序的利用理论大量存在
- 队列无序并不意味着音讯无序
-
-
音讯的反复问题:
- 造成音讯反复的根本原因: 网络不可达
-
所以解决这个问题的办法就是绕过这个问题. 也就是: 如果生产端收到两条一样的音讯, 应该怎么解决?
-
解决方案:
-
生产端解决音讯的业务逻辑放弃幂等性
- 只有放弃幂等性, 不论来多少条反复音讯, 最初解决的后果都一样
- 保障每条音讯都有惟一编号且保障音讯解决胜利与去重表的日志同时呈现
- 利用一张日志表来记录曾经解决胜利的音讯的 ID, 如果新到的音讯 ID 曾经在日志表中, 那么就不再解决这条音讯
-
-
-
-
Kafka,ActiveMQ,RabbitMQ,RocketMQ 各有什么优缺点?
- Dubbo 是什么? 次要利用场景? 外围性能?
-
Dubbo 的实现过程?
-
Dubbo 节点角色?
-
Dubbo 中的调用关系?
- 服务容器负责启动, 加载, 运行服务提供者
- 服务提供者在启动时, 向注册核心注册本人提供的服务
- 服务消费者在启动时, 向注册核心订阅本人所需的服务
- 注册核心返回服务提供者地址列表给消费者, 如果有变更, 注册核心将基于长连贯推送变更数据给消费者
- 服务消费者, 从提供者地址列表中, 基于软负载平衡算法, 抉择一台提供者进行调用. 如果调用失败, 再抉择另一台进行调用
- 服务消费者和服务提供者, 在内存中累计调用次数和调用工夫, 定时每分钟发送统计数据到监控核心
- Dubbo 的注册核心集群宕机, 发布者和订阅者之间还可能通信吗?
- Dubbo 反对哪些协定, 每种协定的利用场景, 优缺点?
- Dubbo 的超时工夫怎么设置?
-
Dubbo 的负载平衡策略有哪些?
-
Random:
- 随机负载平衡策略, 按权重设置随机概率
- 在一个截面上的碰撞概率高, 但调用量越大散布越平均, 而且按概率使用权重后也比拟平均, 有利于动静调整提供者权重
-
RoundRobin:
- 轮循负载平衡策略, 按公约后的权重设置轮循比率
- 存在慢的提供者累积申请的问题
- 比方: 第二台机器很慢, 但没有宕机, 当申请到第二台机器就会卡住, 长此以往, 所有的申请都会卡在 调到第二台机器的时候
-
LeastActive:
- 起码沉闷调用数负载平衡策略, 雷同沉闷数的随机调用. 沉闷数指的是调用前后计数差
- 使慢的提供者收到更少的申请, 因为越慢的提供者的调用前后计数差会越大
-
ConsistentHash:
- 一致性 Hash 负载平衡策略, 雷同的参数申请总是发到同一提供者
- 当某台提供者宕机时, 本来发往该提供者的申请, 基于虚构节点, 平摊到其余提供者, 不会引起激烈变动
- 缺省只对第一个参数 Hash, 如果要批改, 须要批改 < dubbo:parameter key=”hash.arguments” value=”0,1″ />
- 缺省应用 160 份虚构节点, 如果要批改, 须要批改 < dubbo:parameter key=”hash.nodes” value=”320″ >
-
-
Dubbo 集群容错策略?
- Failover: 失败主动切换, 当呈现失败, 重试其余服务器. 通常用于读操作, 但重试会带来更长提早. 能够通过设置retries=”2″ 来设置重试次数, 不蕴含第一次
- Failfast: 疾速失败, 只发动一次调用, 失败立刻报错. 通常用于非幂等性的写操作, 比方新增记录
- Failsafe: 失败平安, 出现异常时, 间接疏忽. 通常用于写入审计日志等操作
- Failback: 失败主动复原, 后盾记录失败申请, 定时重发. 通常用于音讯告诉操作
- Forking: 并行调用多个服务器, 只有一个胜利即返回. 通常用于实时性要求比拟高的读操作, 但须要节约更多服务资源, 能够通过设置 forks=”2″ 来设置最大并行数
- Broadcast: 播送调用所有提供者, 一一调用, 任意一台报错即报错. 通常用于告诉所有提供者更新缓存或日志等本地资源信息
-
Dubbo 的动静代理策略?
-
Dubbo 作为 RPC 框架, 首先要实现的就是跨零碎, 跨网络的服务调用
-
生产方和提供方遵循对立的接口定义
- 生产方调用接口时,Dubbo 将其转换为对立格局的数据结构
- 通过网络传输, 提供方依据规定找到接口实现, 通过反射实现调用
-
生产方获取的是对近程服务的一个代理 Proxy, 提供方因为要反对不同的接口实现, 须要一个包装层Wrapper
- 调用过程:
- 生产方的 Proxy 和提供方的 Wrapper 得以让 Dubbo 构建出简单, 对立的体系
-
这种动静代理与包装是通过 SPI 的插件形式实现的, 接口就是ProxyFactory:
@SPI("javassist") public interface ProxyFactory {@Adaptive({Constants.PROXY_KEY}) <T> T getProxy(Invoker<T> invoker) throws RpcException; @Adaptive({Constants.PROXY_KEY}) <T> invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException; } -
ProxyFactor 有两种实现形式:
- 基于 JDK 的代理实现
- 基于 javassist 的实现
- ProxyFactory 接口上定义了 @SPI(“javassist”), 默认为 javassist 的实现
- 调用过程:
-
-
- Dubbo 有哪些注册核心?
- Dubbo 与 Spring 之间的关系?
- Dubbo 应用的是什么通信框架?
- Dubbo 的平安机制是如何实现的?
- Dubbo 连贯注册核心和直连的区别?
- Dubbo 的通信协议 dubbo 协定为什么采纳异步繁多长连贯的形式?
- Dubbo 的通信协议 dubbo 协定适用范围和利用场景?
-
Dubbo 反对哪些序列化协定?Hessian?Hessian 的数据结构?
- Dubbo 序列化: 阿里基于 Java 的序列化实现
- Hessian2 序列化: Hessian 是一种跨语言的高效二进制的序列化形式. 这里理论不是原生的 Hessian2 序列化, 而是阿里批改过的 Hessian Lite, 是 Dubbo 默认启用的序列化形式
-
Json 序列化: 目前有两种实现:
- 采纳阿里的 fastjson 库
-
采纳 Dubbo 本身实现的简略 Json 库
- 个别状况下,json 这种文本序列化性能不如二进制序列化
- Kryo 和 FST: Kryo 和 FST 的性能广泛优于 Hessian 和 Dubbo 序列化
-
Hessian 序列化和 Java 默认的序列化区别?
-
Hessian 是一个轻量级的 remoting on http 工具, 采纳 Binary RPC 协定, 很适宜发送二进制数据, 同时又具备防火墙穿透能力
- Hessian 反对跨语言串行
- Hessian 序列化比 Java 默认的序列化具备更好的性能和易用性
- Hessian 序列化反对的语言比拟多
-
-
Protoco Buffer 是什么?
- Protoco Buffer 是谷歌出品的一种轻量并且高效的结构化数据存储格局, 性能比 Json,XML 弱小得多
-
Protoco 的序列化和反序列化简略并且速度快. 起因在于:
- 编码和解码形式简略, 只须要简略的数学运算 = 位移等等
- 采纳 Protoco Buffer 本身的框架代码和编译器共同完成
-
Protoco Buffer 的数据压缩成果好, 即序列化后数据量的体积小. 起因在于:
- 采纳独特的编码方式, 比方 Varint,Zigzag 编码方式等等
- 采纳 T – L – V 数据存储形式, 缩小了分隔符的应用并且数据存储得紧凑
-
注册核心宕机了能够持续通信吗?
- 能够
- Dubbo 消费者在利用启动时会从注册核心拉取已注册的生产者的地址接口, 并缓存在本地. 每次调用时, 依照本地存储的地址进行调用
-
ZooKeeper 有什么用?ZooKeeper 原理是什么?
-
ZooKeeper 是一个分布式应用协调系统, 曾经利用到了许多分布式我的项目中, 用来实现
- 对立命名服务
- 状态同步服务
- 集群治理
- 分布式应用配置项的治理
- 每个 Server 在内存中存储了一份数据
- ZooKeeper 启动时, 将从实例中选举一个 leader(Paxo 协定)
- Leader负责解决数据更新等操作 (Zab 协定)
- 当且仅当大多数 Server 在内存中胜利批改数据时, 一个更新操作胜利
-
-
Netty 有什么用?NIO,BIO,AIO 有什么用? 有什么区别?
- Netty是一个网络通信框架
-
Netty 进行事件处理的流程:
- Channel是连贯的通道, 是 ChannelEvent 的产生者
- ChannelPipeline能够了解为 ChannelHandler 的汇合
-
IO 的形式通常分为:
- 同步阻塞的 BIO
- 同步非阻塞的 NIO
- 异步非阻塞的 AIO
-
在应用同步阻塞的 BIO 的网络应用:
- 如果要同时解决多个客户端申请, 或者是在客户端要同时和多个服务器进行通信, 就必须应用多线程来解决
-
同步非阻塞的 NIO 基于 Reactor:
- 当 socket 有流可读或者可写入 socket 时, 操作系统会相应的告诉援用程序进行解决, 利用再将流读取到缓冲区或者写入操作系统
- 这个时候, 不是一个连贯就要对应一个解决线程了. 而是无效的申请, 对应一个线程, 当连贯没有数据时, 是没有工作线程来解决的
-
异步非阻塞的 AIO 与 NIO 不同:
- 当进行读写操作时, 只须要间接调用 API 的read或者 write 办法即可
-
这两种办法均为异步的:
- 对于读操作而言, 当有流可读取时, 操作系统会将可读的流传入 read 办法的缓冲区, 并告诉应用程序
- 对于写操作而言, 当操作系统将 write 办法传递的流写入结束时, 操作系统被动告诉应用程序
- read或者 write 办法都是异步的, 实现后会被动调用回调函数
-
为什么要进行零碎拆分? 拆分不必 Dubbo 能够吗?
-
零碎拆分的分类:
-
从资源角度:
- 利用拆分
- 数据库拆分
-
从采纳的先后顺序:
- 程度扩大
- 垂直拆分
- 业务拆分
- 程度拆分
-
-
是否应用 Dubbo 根据理论业务场景来决定:
- 当垂直利用越来越多, 利用之间的交互不可避免, 将外围业务抽取进去, 作为独立的服务, 逐步造成稳固的服务中心, 使前端利用能更疾速的响应多变的市场需求. 此时, 用于进步业务复用以及整合的分布式框架 RPC 是要害
- 当服务越来越多, 容量的评估, 小服务资源的节约等问题逐步浮现, 此时须要减少一个调度核心基于拜访压力实时治理集群容量, 进步集群的利用率. 此时, 用于进步机器利用率的资源调度和治理核心 SOA 是要害
-
-
Dubbo 和 Thrift 有什么区别?
- Dubbo 反对服务治理, 而 Thrift 不反对
- Thrift 是跨语言 RPC 框架
-
Redis 如何实现分布式锁?
setNX key value
value 保障唯一性, 防止线程 A 开释线程 B 拿到的锁 -
实现分布式锁如果应用 setNX 命令, 那么如果锁的机器宕机了, 其余服务怎么拿失去锁?
设置过期工夫
-
如何来设置过期工夫? 先 set key value, 再设置过期工夫吗? 如果是两条命令,set key value 胜利, 设置过期工夫失败, 一样存在如上问题. 那么如何来保障 set key value 和设置过期工夫的原子操作?
set 命令提供了相应的原子操作命令来保障 set key value 和设置过期工夫的原子操作
-
Redis 是应用的集群吗? 如果是集群, 当客户端执行 setNX 时 Redis 集群, 如何做才认为 set 胜利? 一半集群 set 胜利, 就认为胜利吗? 还是全副 set 胜利才认为胜利?
Redis 集群应用的是多主多从, 当一半以上的主节点 set 胜利, 才算胜利
-
一半胜利就算胜利, 假如 Redis 集群有 a,b,c 三个主节点, 各有一个从节点, 线程 A 在 a,b 主节点 set 胜利, 而在 c 主节点 set 失败, 此时线程 A 获取到锁, 而此时刚好 b 主节点宕机, 刚好数据还没有同步到其从节点, 那么此时从节点 b ’ 降级到主节点, 那么线程 B 对雷同的 key 执行 set 命令来获取锁, 在 b ’ 和 c 节点 set 胜利, 这样同样能够获取到锁, 这个时候呈现了多个线程获取到同一把锁?
-
Redis 缓存, 如何实现更新?
先 Delete 缓存, 再更新 DB, 延时一段时间再 Delete 缓存
或者先更新 DB, 延时一段时间再 Delete 缓存 -
为什么要延时一段时间?
因为如果线程 A 先 Delete 缓存, 此时线程 B 发现缓存中没有数据, 则从 DB 中读出老数据并 reload 到缓存, 线程 A 更新数据库之后, 则缓存与数据库数据库中的数据不统一, 因而须要延时一段时间执行删除
-
如果 Delete 失败?
重试机制
-
Redis 中的数据结构有哪些? 跳表用于哪些场景?
-
volatile 关键字?Lock?
-
并发编程中的问题:
- 原子性问题
- 可见性问题
- 有序性问题
-
volatile:
- volatile 关键字能保障可见性, 只能禁止指令重排序, 不能保障原子性
- 可见性只能保障每次读取的是最新的值, 然而 volatile 无奈保障对变量的操作的原子性
- 在生成的会变语句中退出 Lock 关键字和内存屏障
-
Lock:
- Lock 实现提供了比应用 synchronized 办法和语句可取得的更宽泛的锁定操作, 可能应用更优雅的形式解决线程同步问题
- 用 synchronized 润饰的办法或者语句块在代码执行完之后锁主动开释, 然而应用 Lock 润饰的办法或者语句须要手动开释锁
-
-
Java 每次批改都须要从新编译打包部署, 有没有更好的额办法?
热部署
-
过程间通信有哪几种形式?
- 管道: Pipe
- 命名管道: Named Pipe
- 信号: Signal
- 音讯队列: Message
- 共享内存
- 内存映射: Mapped Memory
- 信号量: Semaphore
- 套接口: Socket
-
Synchronized 润饰的办法实例?
Synchronized 润饰静态方法, 锁定自身不是实例. 非静态方法锁定实例
-
操作系统什么状况下会死锁?
- 死锁: 指多个过程在运行过程中因抢夺资源而造成的一种僵局
-
产生起因: 竞争资源
- 当零碎中多个过程应用共享资源, 并且资源不足以满足需要, 会引起过程对资源的竞争而产生死锁
- 过程间推动的程序不当
- 申请和开释资源的程序不当, 同样也会产生过程死锁
-
产生死锁的四个条件
- 互斥条件: 过程独占资源
- 申请与放弃: 过程因申请资源而阻塞时, 对已取得的资源放弃不放
- 不剥夺条件: 过程曾经取得资源, 在未应用完之前, 不能强行剥夺
- 循环期待: 若干过程之间造成头尾相接的循环期待资源关系
-
如何了解分布式锁?
线上服务器是分布式多台部署的, 常常会面临解决分布式场景下数据一致性问题, 这是就要利用分布式锁来解决这些问题
- 分布式事务有哪些实现形式?
-
微服务的架构设计?
JVM
-
Java 类的初始化程序?
-
Java 类的初始化程序:
- 基类动态代码块, 基类动态成员变量. 并列优先级, 依照代码中呈现的先后顺序执行, 并且只有第一次加载时执行
- 派生类动态代码块, 派生类动态成员变量. 并列优先级, 依照代码中呈现的先后顺序执行, 并且只有第一次加载时执行
- 基类一般代码块, 基类一般成员变量. 并列优先级, 依照代码块中呈现的先后顺序执行
- 基类构造函数.
- 派生类一般代码块, 派生类一般成员变量. 并列优先级, 依照代码块中呈现的先后顺序执行
- 派生类构造函数.
-
- 为什么要进行分代?
-
对办法区和永恒区的了解以及两者的区别?
- 办法区 是JVM 标准 中要求的 , 永恒区 是 Hotspot 虚拟机对办法区的 具体实现
- 办法区是标准, 永恒区是实现形式(JDK 1.8 当前做了扭转)
-
一个 Java 类有 3 个文件, 编译后有几个 class 文件?
- 文件中有几个类, 编译后就有几个 class 文件
-
局部变量应用前须要显式的赋值, 否则编译通过不了, 为什么要这样设计?
- 成员变量是能够不经初始化的, 在类加载过程的筹备阶段即能够给成员变量赋予默认值.
- 局部变量在应用之前须要显式赋予初始值
- javac 不是推断不出不能够这样做, 对于成员变量而言, 其赋值和取值拜访的先后顺序具备不确定性, 对于一个成员变量能够在一个办法调用前赋值, 也能够在办法调用后进行赋值, 这是运行时产生的, 编译器确定不了, 交给 JVM 做比拟适合
-
对于局部变量而言, 局部变量的赋值和拜访程序是确定的, 这样设计是一种束缚, 尽最大水平缩小使用者犯错的可能性:
- 倘若局部变量能够应用默认值, 可能总会无意间遗记赋值, 进而导致不可预期的状况呈现
- JVM 的内存分区?
- 堆内存的分区以及每个分区的垃圾回收算法? 回收器 G1,CMS 有标记革除, 标记整顿法?
- 如何排查 Full GC,OOM?
- 线程个数太多会导致 OOM, 然而这里的线程包含程序的所有线程吗? 比方包含 pigeon 的线程池吗?
-
JVM 中类的加载过程, 双亲委派模型中有哪些办法?
-
类加载过程:
- 加载
- 验证: 验证阶段作用是保障 Class 文件的字节流蕴含的信息合乎 JVM 标准, 不会给 JVM 造成挫伤
- 筹备: 筹备阶段为变量分配内存并设置类变量的初始化
- 解析: 解析过程是将常量池内的符号援用替换成间接援用
- 初始化
-
双亲委派模型中的办法: 双亲委派是指如果一个类收到类加载申请, 不会本人先尝试加载, 先找父类加载器实现. 当顶层启动类加载器示意无奈加载这个类的时候, 子类才会本人去加载. 当回到最开始的发起者加载器还无奈加载时, 并不会向下找, 而是抛出 ClassNotFound 异样
- 启动 (Bootstrap) 类加载器
- 规范扩大 (Extension) 类加载器
- 应用程序 (Application) 类加载器
- 上下文 (Custom) 类加载器
- 意义是避免内存中呈现多份同样的字节码
-
- 垃圾收集器理解哪些?
- GC ROOTS 包含哪些?
-
GC 算法? 什么样的对象算是可回收对象? 可达性剖析?CMS 收集器?
-
JVM 如何判断一个对象曾经变成可回收的垃圾:
- 援用计数器法: 援用计数器无奈解决循环援用的问题
- 根搜索算法: 从一系列的 GC Roots 对象开始向下搜寻, 搜寻的门路称为援用链. 当一个对象到 GC Roots 之间没有援用链时称为援用不可达. 援用不可达的对象被认为是可回收对象
-
几种垃圾回收器:
- Serial New 或者 Serial Old: 串行
- Parrallel New: 并行
- Parrallel Scavenge
- Parrallel Old
- G1: 一款并行与并发收集器, 并且可建设可预测的进展工夫模型, 整体上是基于标记清理, 部分采纳复制
- CMS
- CMS 收集器是一个以取得最短回收进展工夫为指标的收集器, 是一种并发收集器, 采纳的是 Mark – Sweep 算法
-
- JVM 中的 GC 复制算法是怎么实现的?
-
JVM 分为哪些区? 每一个区的作用?
- 办法区(Method): 被所有线程共享, 办法区蕴含所有的类信息和动态变量
- 堆(Heap): 被所有的线程共享, 寄存对象实例以及数组,Java 堆是 GC 的次要区域
- 栈(Stack): 每一个线程蕴含一栈区, 栈中保留一些局部变量
- 程序计数器: 以后线程执行的字节码行指示器
-
JVM 新生代, 老年代, 长久代. 都存储些什么内容?
- 新生代寄存所有新生成的对象
- 老年代寄存的都是一些生命周期较长的对象
- 长久代次要寄存的是 Java 类的类信息, 与垃圾收集要收集的 Java 对象关系不大
-
内存溢出和内存泄露?
- 内存溢出: out of memory, 程序申请内存时, 没有足够的内存
- 内存泄露: 垃圾对象无奈回收, 可是应用 memory analyzer 工具查看泄露
-
过程与线程?
- 过程: 运行中的程序, 具备独立性, 动态性, 并发性
- 线程: 指过程中的程序执行流
-
过程与线程的区别:
- 过程间不共享内存
- 创立过程进行资源分配的代价要大得多, 所以多线程在高并发的环境中效率高
-
序列化和反序列化?
- 序列化: 将 Java 对象转化为字节序列
- 反序列化: 将字节序列转化为 Java 对象
- 序列化和反序列化次要是为了 Java 线程间的通信, 实现对象传递. 只有实现了 Serializable 或者 Externalizable 接口类对象才可被序列化
-
64 位 JVM 中,int 的长度是多长?
在 JVM 中,int 类型的变量的长度是一个固定值, 与平台无关,4 个字节, 长度为 32 位
-
Java 中 WeakReference 与 SoftReference 的区别?
-
Java 中一共有四种类型的援用:
- StrongReference
- SoftReference
- WeakReference
- PhantomReference
- StrongReference 是 Java 的默认援用实现, 会尽可能长时间的存活于 JVM 内, 当没有任何对象指向时将会被 GC 回收
- SoftReference 会尽可能长的保留援用直到 JVM 内存不足时才会被回收, 通过虚拟机保障. 这一个性使得 SofeReference 非常适合缓存利用
- WeakReference 是一个弱援用, 当所援用的对象在 JVM 内不再有强援用时, 将被 GC 回收
-
WeakReference 和 SoftReference 的区别:
- WeakReference 与 SoftReference 都有利于进步 GC 和内存的效率
- WeakReference 一旦失去最初一个强援用, 就会被 GC 回收
- SoftReference 会尽可能长的保留援用直到 JVM 内存不足时才会被回收, 通过虚拟机保障
-
- JVM 内存的划分?
- Java 堆的划分?
-
Java 中堆和栈有什么区别?
- Java 中的堆和栈属于不同的内存区域, 应用目标也不同
- 栈通常用于保留办法帧和局部变量. 而对象总是在堆上调配
- 栈通常比堆小, 也不会在多个线程之间共享, 而堆是被整个 JVM 所有线程共享
-
Java 堆空间及 GC?
-
Java 堆空间:
- 当通过 Java 命令启动 Java 过程的时候, 会分配内存, 内存的一部分用于创立堆空间
- 当程序中创建对象的时候, 就从堆空间中分配内存
-
GC:
- GC 是 JVM 外部的一个过程, 回收有效对象的内存用于未来的调配
-
- 哪些对象会被 JVM 回收?
网络
-
TCP 如何保障可靠性传输? 三次握手过程?
-
在 TCP 连贯中, 数据流必须以正确的程序送达对方
–TCP 可靠性:- 通过 程序编码 和确认(ACK) 来实现的
-
TCP 连贯是通过三次握手进行初始化的, 三次握手的目标是同步连贯单方序列号和确认号并替换 TCP 窗口大小信息:
- 第一次: 客户端发动连贯
- 第二次: 示意服务器收到了客户端申请
- 第三次: 示意客户端收到了服务器反馈
-
-
如何辨认 session?
- 在 cookie 中存储的session id
- HTTP 报文构造?
- HTTP 状态码?
-
Linux 下的常用命令:
- cd: 用来扭转所在目录. cd / – 转到根目录, cd ~ – 转到用户目录
- ls: 用来查看目录的内容
- cp: 用来拷贝文件. cp sourceFileName targetFileName
- mv: 挪动文件. mv t.txt Document
-
罕用的 Hash 算法有哪些?
- 加法 Hash: 所谓的加法 Hash 就是把输出元素一个一个加起来形成最初的后果
- 位运算 Hash: 这种类型的 Hash 函数通过利用各种位运算, 比方移位或者异或来充沛的混合输入元素
- 乘法 Hash: 33*hash + key.charAt(i)
-
什么是一致性 Hash?
-
一致性 Hash 的设计指标是为了解决因特网中的热点 (Hot spot) 问题, 一致性 Hash 算法提出了在动态变化的 Cache 环境中, 断定 Hash 算法好坏的四个定义:
- 平衡性 :Balance
- 枯燥性 :Monotonicity
- 分散性 :Spread
- 负载 :Load
-
-
表单提交中,get 和 post 的区别?
- get 是从服务器获取信息, post 是向服务器传信息
- get 传送的数据量比拟小, post 传递的数据量能够比拟大
- get 的安全性比 post 低
-
TCP 协定和 UDP 协定有什么区别?
- TCP: Tranfer Control Protocol, 是一种面向连贯的保障传输协定, 在传输数据流之前, 单方会建设一条虚构的通信道, 能够极少过错传输数据
-
UDP: User DataGram Protocol, 是一种无连贯的协定, 应用 UDP 时, 每一个数据段都是一个独立的信息, 包含残缺的源地址和目的地, 在网络上以任何可能的门路达到目的地. 因而, 是否达到目的地, 以及达到目的地的工夫和内容的完整性都不能保障
- TCP 比 UDP 多了建设连贯的工夫. 绝对 UDP 而言,TCP 具备更高的安全性和可靠性
- TCP 协定传输的大小不限度, 一旦连贯被建设, 单方能够依照吧肯定的格局传输大量的数据, 而 UDP 是一个不牢靠协定, 大小有限度, 每次不能超过64K
- Java IO 模型有哪几种?
- 同步和异步, 阻塞和非阻塞的区别?
- Netty 根本介绍