Skip to content

Commit

Permalink
去哪儿面经
Browse files Browse the repository at this point in the history
  • Loading branch information
itwanger committed Jul 11, 2024
1 parent 760b05c commit bfce1d4
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 52 deletions.
8 changes: 8 additions & 0 deletions docs/sidebar/sanfene/collection.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,14 @@ private E dequeue() {

像 Vector、Hashtable、ConcurrentHashMap、CopyOnWriteArrayList、ConcurrentLinkedQueue、ArrayBlockingQueue、LinkedBlockingQueue 这些都是线程安全的。

#### Java 集合用过哪些?Collection 继承了哪些接口?

最经常用的就是封装了动态数组的 ArrayList 和封装了链表的 LinkedList;以及键值对 HashMap。

Collection 继承了 Iterable 接口,这意味着所有实现 Collection 接口的类都必须实现 `iterator()` 方法,之后就可以使用增强型 for 循环遍历集合中的元素了。

![二哥的 Java 进阶之路:Collection源码](https://cdn.tobebetterjavaer.com/stutymore/collection-20240711092853.png)

> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的用友金融一面原题:你了解哪些集合框架?
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的华为一面原题:说下 Java 容器和 HashMap
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的小米暑期实习同学 E 一面面试原题:你了解哪些集合?
Expand Down
48 changes: 47 additions & 1 deletion docs/sidebar/sanfene/javase.md
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,51 @@ public class Dog extends Animal {

![二哥的 Java 进阶之路:接口不能定义构造方法](https://cdn.tobebetterjavaer.com/stutymore/javase-20240512090855.png)

#### 接口可以多继承吗?

接口可以多继承,一个接口可以继承多个接口,使用逗号分隔。

```java
interface InterfaceA {
void methodA();
}

interface InterfaceB {
void methodB();
}

interface InterfaceC extends InterfaceA, InterfaceB {
void methodC();
}

class MyClass implements InterfaceC {
public void methodA() {
System.out.println("Method A");
}

public void methodB() {
System.out.println("Method B");
}

public void methodC() {
System.out.println("Method C");
}

public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.methodA();
myClass.methodB();
myClass.methodC();
}
}
```

在上面的例子中,InterfaceA 和 InterfaceB 是两个独立的接口。

InterfaceC 继承了 InterfaceA 和 InterfaceB,并且定义了自己的方法 methodC。

MyClass 实现了 InterfaceC,因此需要实现 InterfaceA 和 InterfaceB 中的方法 methodA 和 methodB,以及 InterfaceC 中的方法 methodC。

#### 继承和抽象的区别?

继承是一种允许子类继承父类属性和方法的机制。通过继承,子类可以重用父类的代码。
Expand Down Expand Up @@ -707,7 +752,8 @@ public class Test {
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的小公司面经合集同学 1 Java 后端面试原题:抽象类和接口有什么区别?
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的用友面试原题:抽象类和接口的区别?抽象类可以定义构造方法吗?
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的百度面经同学 1 文心一言 25 实习 Java 后端面试原题:继承和抽象的区别
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的美团同学 2 优选物流调度技术 2 面面试原题:抽象类能写构造方法吗(能)接口能吗(不能)为什么二者有这样的区别
> 4. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的美团同学 2 优选物流调度技术 2 面面试原题:抽象类能写构造方法吗(能)接口能吗(不能)为什么二者有这样的区别
> 5. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的去哪儿同学 1 技术 2 面面试原题:接口可以多继承吗
### 22.成员变量与局部变量的区别有哪些?

Expand Down
40 changes: 23 additions & 17 deletions docs/sidebar/sanfene/javathread.md
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,8 @@ Java 内存模型里面的本地内存,可能对应的是 L1 缓存或者 L2

> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的帆软同学 3 Java 后端一面的原题:为什么线程要用自己的内存
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的比亚迪面经同学 3 Java 技术一面面试原题:说一下 JMM
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的去哪儿面经同学 1 技术二面面试原题:说说 JMM模型

### 19.说说你对原子性、可见性、有序性的理解?

Expand Down Expand Up @@ -1509,23 +1511,24 @@ public void increment() {
### 25.synchronized 的实现原理?

> synchronized 是怎么加锁的呢?
#### synchronized 是怎么加锁的呢?

我们使用 synchronized 的时候,发现不用自己去 lock 和 unlock,是因为 JVM 帮我们把这个事情做了
synchronized 是 JVM 帮我们实现的,因此在使用的时候不用手动去 lock 和 unlock,JVM 会帮我们自动加锁和解锁

1. synchronized 修饰代码块时,JVM 采用`monitorenter``monitorexit`两个指令来实现同步,`monitorenter` 指令指向同步代码块的开始位置, `monitorexit` 指令则指向同步代码块的结束位置。
①、synchronized 修饰代码块时,JVM 会通过 `monitorenter``monitorexit` 两个指令来实现同步:

反编译一段 synchronized 修饰代码块代码,`javap -c -s -v -l SynchronizedDemo.class`,可以看到相应的字节码指令。
- `monitorenter` 指向同步代码块的开始位置
- `monitorexit` 指向同步代码块的结束位置。

![monitorenter和monitorexit](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/sidebar/sanfene/javathread-30.png)
使用 `javap -c -s -v -l SynchronizedDemo.class` 反编译一段 synchronized 代码块时,可以看到 monitorenter 和 monitorexit 指令。

2. synchronized 修饰同步方法时,JVM 采用`ACC_SYNCHRONIZED`标记符来实现同步,这个标识指明了该方法是一个同步方法。
![三分恶面渣逆袭:monitorenter和monitorexit](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/sidebar/sanfene/javathread-30.png)

同样可以写段代码反编译看一下
②、synchronized 修饰方法时,JVM 会通过 `ACC_SYNCHRONIZED` 标记符来实现同步

![synchronized修饰同步方法](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/sidebar/sanfene/javathread-31.png)
![三分恶面渣逆袭:synchronized修饰同步方法](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/sidebar/sanfene/javathread-31.png)

> synchronized 锁住的是什么呢?
#### synchronized 锁住的是什么呢?

monitorenter、monitorexit 或者 ACC_SYNCHRONIZED 都是**基于 Monitor 实现**的。

Expand Down Expand Up @@ -1570,7 +1573,7 @@ ObjectMonitor() {

- 就诊结束后,**走出就诊室**,候诊室的**下一位候诊患者**进入就诊室。

![就诊-图片来源参考[18]](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/sidebar/sanfene/javathread-32.png)
![图片来源于网络:就诊](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/sidebar/sanfene/javathread-32.png)

这个过程就和 Monitor 机制比较相似:

Expand All @@ -1585,6 +1588,12 @@ ObjectMonitor() {
- monitorenter,在判断拥有同步标识 ACC_SYNCHRONIZED 抢先进入此方法的线程会优先拥有 Monitor 的 owner ,此时计数器 +1。
- monitorexit,当执行完退出后,计数器 -1,归 0 后被其他进入的线程获得。

#### 会不会牵扯到 os 层面呢?

会,synchronized 升级为重量级锁时,依赖于操作系统的互斥量(mutex)来实现,mutex 用于保证任何给定时间内,只有一个线程可以执行某一段特定的代码段。

> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的去哪儿面经同学 1 技术二面面试原题:synchronized底层,会不会牵扯到os层面
### 26.除了原子性,synchronized 可见性,有序性,可重入性怎么实现?

#### synchronized 怎么保证可见性?
Expand Down Expand Up @@ -1621,17 +1630,13 @@ synchronized 之所以支持可重入,是因为 Java 的对象头包含了一

#### 什么是锁升级?

在 Java 对象头里,有一块结构,叫`Mark Word`,里面会记录锁的状态。

Mark Word 会记录对象自身的运行数据,如**哈希码、GC 分代年龄、锁状态标志、偏向时间戳(Epoch)** 等。
锁升级是 Java 虚拟机中的一个优化机制,用于提高多线程环境下 synchronized 的并发性能。锁升级涉及从较轻的锁状态(如无锁或偏向锁)逐步升级到较重的锁状态(如轻量级锁和重量级锁),以适应不同程度的竞争情况。

其中的锁状态标志位就是用来记录锁的状态的,有四种状态
Java 对象头里的 `Mark Word` 会记录锁的状态,一共有四种状态

①、无锁状态,在这个状态下,没有线程试图获取锁。

②、偏向锁,当第一个线程访问同步块时,锁会进入偏向模式。

Mark Word 会被设置为偏向模式,并且存储了获取它的线程 ID。
②、偏向锁,当第一个线程访问同步块时,锁会进入偏向模式。Mark Word 会被设置为偏向模式,并且存储了获取它的线程 ID。

偏向锁的目的是消除同一线程的后续锁获取和释放的开销。如果同一线程再次请求锁,就无需再次同步。

Expand Down Expand Up @@ -1705,6 +1710,7 @@ Mark Word 会被设置为偏向模式,并且存储了获取它的线程 ID。

> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的小米春招同学 K 一面面试原题:synchronized 锁升级过程
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的农业银行同学 1 面试原题:Java 的锁的优化
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的去哪儿面经同学 1 技术二面面试原题:锁升级,synchronized底层,会不会牵扯到os层面
### 28.说说 synchronized 和 ReentrantLock 的区别?

Expand Down
11 changes: 6 additions & 5 deletions docs/sidebar/sanfene/jvm.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ JVM 维护一个列表,记录堆中所有未占用的内存块,每个空间

可以通过 `java -XX:+PrintFlagsFinal -version | grep UseCompressedOops` 命令来查看当前 JVM 是否开启了压缩指针。

![](https://cdn.tobebetterjavaer.com/stutymore/jvm-20240320220408.png)
![二哥的 Java 进阶之路:查看 JVM 是否开启压缩指针](https://cdn.tobebetterjavaer.com/stutymore/jvm-20240320220408.png)

如果压缩指针开启,会看到类似以下的输出,其中 bool UseCompressedOops 的值为 true。

Expand All @@ -236,7 +236,7 @@ JVM 维护一个列表,记录堆中所有未占用的内存块,每个空间

③、**对齐填充**,为了使对象的总大小是 8 字节的倍数(这在大多数现代计算机体系结构中是最优访问边界),JVM 可能会在对象末尾添加一些填充。这部分是为了满足内存对齐的需求,并不包含任何具体的数据。

**为什么非要进行 8 字节对齐呢?**
#### 为什么非要进行 8 字节对齐呢?

这是因为 CPU 进行内存访问时,一次寻址的指针大小是 8 字节,正好是 L1 缓存行的大小。如果不进行内存对齐,则可能出现跨缓存行访问,导致额外的缓存行加载,降低了 CPU 的访问效率。

Expand Down Expand Up @@ -296,7 +296,7 @@ public class JOLSample {

第三步,运行代码,查看输出结果:

![](https://cdn.tobebetterjavaer.com/stutymore/jvm-20240320223653.png)
![二哥的 Java 进阶之路:JOL 运行结果](https://cdn.tobebetterjavaer.com/stutymore/jvm-20240320223653.png)

可以看到有 OFFSET、SIZE、TYPE DESCRIPTION、VALUE 这几个名词头,它们的含义分别是

Expand All @@ -315,7 +315,7 @@ public class JOLSample {

而 HotSpot JVM 默认开启了压缩指针,因此在 64 位 JVM 上,对象引用占用 4 字节。

![](https://cdn.tobebetterjavaer.com/stutymore/jvm-20240320224701.png)
![dijia478:对象头](https://cdn.tobebetterjavaer.com/stutymore/jvm-20240320224701.png)

我们可以通过下面这个例子来验证一下:

Expand All @@ -334,11 +334,12 @@ class ReferenceSizeExample {

运行代码,查看输出结果:

![](https://cdn.tobebetterjavaer.com/stutymore/jvm-20240320231059.png)
![二哥的 Java 进阶之路:对象的引用有多大?](https://cdn.tobebetterjavaer.com/stutymore/jvm-20240320231059.png)

ReferenceHolder.reference 字段位于偏移量 12,大小为 4 字节。这表明在当前的 JVM 配置下(64 位 JVM 且压缩指针开启),对象引用占用的内存大小为 4 字节。

> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的帆软同学 3 Java 后端一面的原题:Object a = new object()的大小,对象引用占多少大小?
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的去哪儿面经同学 1 技术二面面试原题:Object底层的数据结构(蒙了)
### 9.对象怎么访问定位?

Expand Down
1 change: 1 addition & 0 deletions docs/sidebar/sanfene/mysql.md
Original file line number Diff line number Diff line change
Expand Up @@ -1435,6 +1435,7 @@ create index idx_name on students(name);
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的腾讯面经同学 23 QQ 后台技术一面面试原题:MySQL 索引,为什么用 B+树
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的小米面经同学 E 第二个部门 Java 后端技术一面面试原题:为什么需要索引
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的小公司面经同学 5 Java 后端面试原题:数据库索引讲一下,然后为什么会加快查询速度,我讲到了 B+树,然后问了 B 数与 B+树区别
> 4. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的去哪儿面经同学 1 技术二面面试原题:mysql为什么用索引
### 28.能简单说一下索引的分类吗?

Expand Down
Loading

0 comments on commit bfce1d4

Please sign in to comment.