Files
interview/questions/05-并发编程/Java并发编程基础.md
yasinshaw 0e46a367c4 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>
2026-03-01 00:10:53 +08:00

4.6 KiB
Raw Permalink Blame History

Java 并发编程基础

问题

  1. 进程和线程的区别?
  2. 创建线程有哪些方式?
  3. synchronized 关键字的原理?
  4. volatile 关键字的作用?
  5. CASCompare And Swap的原理和 ABA 问题?
  6. ThreadLocal 的原理和内存泄漏问题?

标准答案

1. 进程 vs 线程

特性 进程 线程
资源 独立内存、文件描述符 共享进程资源
通信 IPC管道、消息队列、共享内存 共享内存
上下文切换 慢(需保存更多状态)
开销

2. 创建线程的方式

方式 1继承 Thread

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread running");
    }
}
new MyThread().start();

方式 2实现 Runnable

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Runnable running");
    }
}
new Thread(new MyRunnable()).start();

方式 3实现 Callable有返回值

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 原理

字节码层面

// 同步方法
public synchronized void method() { }
// 字节码ACC_SYNCHRONIZED

// 同步代码块
synchronized (object) { }
// 字节码monitorenter、monitorexit

对象头

Mark Word32 位 JVM
┌────────────┬────────────┬──────────────┐
│ 锁状态     │ 29 位或2位 │ 是否是偏向锁  │
├────────────┼────────────┼──────────────┤
│ 无锁       │ 对象 Hash  │ 01           │
│ 偏向锁     │ 线程 ID   │ 01           │
│ 轻量级锁   │ 栈中 Lock Record | 00   │
│ 重量级锁   │ 管程指针   │ 10           │
└────────────┴────────────┴──────────────┘

锁升级

无锁 → 偏向锁 → 轻量级锁CAS 自旋) → 重量级锁(阻塞)

4. volatile 关键字

作用

  1. 保证可见性JMM主内存与工作内存
  2. 禁止指令重排序

示例

private volatile boolean running = true;

public void stop() {
    running = false;  // 立即对所有线程可见
}

不能保证原子性

private volatile int count = 0;

// ❌ 非线程安全
count++;  // read → modify → write非原子操作

// ✅ 线程安全
synchronized (this) {
    count++;
}

5. CAS 和 ABA 问题

CASCompare And Swap

// Unsafe.compareAndSwapInt(object, offset, expect, update)
// 如果当前值 == 期望值,则更新为 update

AtomicInteger atomic = new AtomicInteger(0);
atomic.compareAndSet(0, 1);  // CAS 操作

ABA 问题

线程 A读取值 A
线程 BA → B → A
线程 ACAS 成功(不知道值已变化)

解决版本号AtomicStampedReference

AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0);

int oldStamp = ref.getStamp();
ref.compareAndSet(100, 101, oldStamp, oldStamp + 1);  // 版本号也参与 CAS

6. ThreadLocal

原理

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);
}

内存泄漏

// ❌ 可能导致内存泄漏
private static ThreadLocal<byte[]> data = new ThreadLocal<>();

public void process() {
    data.set(new byte[1024 * 1024]);  // 1MB
    // 未调用 remove()
}

原因

  • ThreadLocal 是弱引用,但 value 是强引用
  • 线程不销毁value 不会回收

解决

try {
    data.set(new byte[1024 * 1024]);
    // 业务逻辑
} finally {
    data.remove();  // 必须
}

7. 阿里 P7 加分项

深度理解

  • 理解 JMMJava 内存模型)
  • 理解 happens-before 原则
  • 理解 synchronized 的优化(偏向锁、轻量级锁)

实战经验

  • 有并发问题的排查经验
  • 有性能优化经验(减少锁竞争)
  • 有死锁的排查和解决经验