# 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 { @Override public String call() throws Exception { return "Callable result"; } } FutureTask 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 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 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 的优化(偏向锁、轻量级锁) **实战经验**: - 有并发问题的排查经验 - 有性能优化经验(减少锁竞争) - 有死锁的排查和解决经验