refactor: rename files to Chinese and organize by category
Organized 50 interview questions into 12 categories: - 01-分布式系统 (9 files): 分布式事务, 分布式锁, 一致性哈希, CAP理论, etc. - 02-数据库 (2 files): MySQL索引优化, MyBatis核心原理 - 03-缓存 (5 files): Redis数据结构, 缓存问题, LRU算法, etc. - 04-消息队列 (1 file): RocketMQ/Kafka - 05-并发编程 (4 files): 线程池, 设计模式, 限流策略, etc. - 06-JVM (1 file): JVM和垃圾回收 - 07-系统设计 (8 files): 秒杀系统, 短链接, IM, Feed流, etc. - 08-算法与数据结构 (4 files): B+树, 红黑树, 跳表, 时间轮 - 09-网络与安全 (3 files): TCP/IP, 加密安全, 性能优化 - 10-中间件 (4 files): Spring Boot, Nacos, Dubbo, Nginx - 11-运维 (4 files): Kubernetes, CI/CD, Docker, 可观测性 - 12-面试技巧 (1 file): 面试技巧和职业规划 All files renamed to Chinese for better accessibility and organized into categorized folders for easier navigation. Generated with [Claude Code](https://claude.com/claude-code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
208
questions/05-并发编程/Java并发编程基础.md
Normal file
208
questions/05-并发编程/Java并发编程基础.md
Normal file
@@ -0,0 +1,208 @@
|
||||
# Java 并发编程基础
|
||||
|
||||
## 问题
|
||||
|
||||
1. 进程和线程的区别?
|
||||
2. 创建线程有哪些方式?
|
||||
3. synchronized 关键字的原理?
|
||||
4. volatile 关键字的作用?
|
||||
5. CAS(Compare And Swap)的原理和 ABA 问题?
|
||||
6. ThreadLocal 的原理和内存泄漏问题?
|
||||
|
||||
---
|
||||
|
||||
## 标准答案
|
||||
|
||||
### 1. 进程 vs 线程
|
||||
|
||||
| 特性 | 进程 | 线程 |
|
||||
|------|------|------|
|
||||
| **资源** | 独立内存、文件描述符 | 共享进程资源 |
|
||||
| **通信** | IPC(管道、消息队列、共享内存) | 共享内存 |
|
||||
| **上下文切换** | 慢(需保存更多状态) | 快 |
|
||||
| **开销** | 大 | 小 |
|
||||
|
||||
---
|
||||
|
||||
### 2. 创建线程的方式
|
||||
|
||||
**方式 1:继承 Thread**
|
||||
```java
|
||||
class MyThread extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("Thread running");
|
||||
}
|
||||
}
|
||||
new MyThread().start();
|
||||
```
|
||||
|
||||
**方式 2:实现 Runnable**
|
||||
```java
|
||||
class MyRunnable implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("Runnable running");
|
||||
}
|
||||
}
|
||||
new Thread(new MyRunnable()).start();
|
||||
```
|
||||
|
||||
**方式 3:实现 Callable(有返回值)**
|
||||
```java
|
||||
class MyCallable implements Callable<String> {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
return "Callable result";
|
||||
}
|
||||
}
|
||||
FutureTask<String> future = new FutureTask<>(new MyCallable());
|
||||
new Thread(future).start();
|
||||
String result = future.get();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. synchronized 原理
|
||||
|
||||
**字节码层面**:
|
||||
```java
|
||||
// 同步方法
|
||||
public synchronized void method() { }
|
||||
// 字节码:ACC_SYNCHRONIZED
|
||||
|
||||
// 同步代码块
|
||||
synchronized (object) { }
|
||||
// 字节码:monitorenter、monitorexit
|
||||
```
|
||||
|
||||
**对象头**:
|
||||
```
|
||||
Mark Word(32 位 JVM)
|
||||
┌────────────┬────────────┬──────────────┐
|
||||
│ 锁状态 │ 29 位或2位 │ 是否是偏向锁 │
|
||||
├────────────┼────────────┼──────────────┤
|
||||
│ 无锁 │ 对象 Hash │ 01 │
|
||||
│ 偏向锁 │ 线程 ID │ 01 │
|
||||
│ 轻量级锁 │ 栈中 Lock Record | 00 │
|
||||
│ 重量级锁 │ 管程指针 │ 10 │
|
||||
└────────────┴────────────┴──────────────┘
|
||||
```
|
||||
|
||||
**锁升级**:
|
||||
```
|
||||
无锁 → 偏向锁 → 轻量级锁(CAS 自旋) → 重量级锁(阻塞)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. volatile 关键字
|
||||
|
||||
**作用**:
|
||||
1. **保证可见性**(JMM,主内存与工作内存)
|
||||
2. **禁止指令重排序**
|
||||
|
||||
**示例**:
|
||||
```java
|
||||
private volatile boolean running = true;
|
||||
|
||||
public void stop() {
|
||||
running = false; // 立即对所有线程可见
|
||||
}
|
||||
```
|
||||
|
||||
**不能保证原子性**:
|
||||
```java
|
||||
private volatile int count = 0;
|
||||
|
||||
// ❌ 非线程安全
|
||||
count++; // read → modify → write(非原子操作)
|
||||
|
||||
// ✅ 线程安全
|
||||
synchronized (this) {
|
||||
count++;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. CAS 和 ABA 问题
|
||||
|
||||
**CAS(Compare And Swap)**:
|
||||
```java
|
||||
// Unsafe.compareAndSwapInt(object, offset, expect, update)
|
||||
// 如果当前值 == 期望值,则更新为 update
|
||||
|
||||
AtomicInteger atomic = new AtomicInteger(0);
|
||||
atomic.compareAndSet(0, 1); // CAS 操作
|
||||
```
|
||||
|
||||
**ABA 问题**:
|
||||
```
|
||||
线程 A:读取值 A
|
||||
线程 B:A → B → A
|
||||
线程 A:CAS 成功(不知道值已变化)
|
||||
```
|
||||
|
||||
**解决:版本号(AtomicStampedReference)**:
|
||||
```java
|
||||
AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0);
|
||||
|
||||
int oldStamp = ref.getStamp();
|
||||
ref.compareAndSet(100, 101, oldStamp, oldStamp + 1); // 版本号也参与 CAS
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. ThreadLocal
|
||||
|
||||
**原理**:
|
||||
```java
|
||||
public void set(T value) {
|
||||
Thread t = Thread.currentThread();
|
||||
ThreadLocalMap map = t.threadLocals;
|
||||
if (map != null)
|
||||
map.set(this, value); // key 是 ThreadLocal 对象,value 是值
|
||||
else
|
||||
createMap(t, value);
|
||||
}
|
||||
```
|
||||
|
||||
**内存泄漏**:
|
||||
```java
|
||||
// ❌ 可能导致内存泄漏
|
||||
private static ThreadLocal<byte[]> data = new ThreadLocal<>();
|
||||
|
||||
public void process() {
|
||||
data.set(new byte[1024 * 1024]); // 1MB
|
||||
// 未调用 remove()
|
||||
}
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- ThreadLocal 是弱引用,但 value 是强引用
|
||||
- 线程不销毁,value 不会回收
|
||||
|
||||
**解决**:
|
||||
```java
|
||||
try {
|
||||
data.set(new byte[1024 * 1024]);
|
||||
// 业务逻辑
|
||||
} finally {
|
||||
data.remove(); // 必须
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7. 阿里 P7 加分项
|
||||
|
||||
**深度理解**:
|
||||
- 理解 JMM(Java 内存模型)
|
||||
- 理解 happens-before 原则
|
||||
- 理解 synchronized 的优化(偏向锁、轻量级锁)
|
||||
|
||||
**实战经验**:
|
||||
- 有并发问题的排查经验
|
||||
- 有性能优化经验(减少锁竞争)
|
||||
- 有死锁的排查和解决经验
|
||||
Reference in New Issue
Block a user