1. Java线程基础概念解析
线程作为Java并发编程的核心概念,理解其本质是掌握多线程编程的第一步。线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。在Java中,每个线程都对应一个Thread类的实例。
1.1 线程与进程的区别
线程和进程是现代操作系统的两个基本概念,它们的主要区别体现在以下几个方面:
- 资源分配 :进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位
- 开销差异 :进程拥有独立的代码和数据空间,切换开销大;线程共享进程资源,切换开销小
- 内存共享 :同一进程的线程共享地址空间和资源,进程间资源相互独立
- 健壮性 :一个线程崩溃会导致整个进程终止,而进程崩溃不会影响其他进程
// 进程与线程的关系示例
public class ProcessAndThread {
public static void main(String[] args) {
// 主线程(进程中的第一个线程)
System.out.println("Main thread: " + Thread.currentThread().getName());
// 创建新线程
new Thread(() -> {
System.out.println("New thread: " + Thread.currentThread().getName());
}).start();
}
}
1.2 线程的生命周期
Java线程在其生命周期中会经历多种状态:
- 新建(NEW) :线程对象刚被创建,但尚未启动
- 就绪(RUNNABLE) :调用start()后,线程等待CPU时间片
- 运行(RUNNING) :线程获得CPU时间片,执行run()方法
- 阻塞(BLOCKED) :线程暂时放弃CPU使用权
- 终止(TERMINATED) :线程执行完毕或异常退出
// 线程状态观察示例
public class ThreadStateDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("Before start: " + thread.getState()); // NEW
thread.start();
System.out.println("After start: " + thread.getState()); // RUNNABLE
Thread.sleep(500);
System.out.println("During sleep: " + thread.getState()); // TIMED_WAITING
thread.join();
System.out.println("After finish: " + thread.getState()); // TERMINATED
}
}
2. Java线程创建与管理
2.1 线程创建的三种方式
Java提供了多种创建线程的方式,每种方式都有其适用场景:
- 继承Thread类
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread running by extending Thread");
}
}
// 使用
new MyThread().start();
- 实现Runnable接口
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Thread running by implementing Runnable");
}
}
// 使用
new Thread(new MyRunnable()).start();
- 实现Callable接口(带返回值)
class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "Result from Callable";
}
}
// 使用
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new MyCallable());
System.out.println(future.get()); // 获取返回值
executor.shutdown();
提示:实际开发中推荐使用Runnable或Callable接口方式,因为Java不支持多重继承,使用接口更灵活。
2.2 线程的基本操作
2.2.1 线程启动与中断
正确启动线程应该调用start()方法而非直接调用run()方法。start()会创建新线程执行run()方法,而直接调用run()会在当前线程执行。
// 正确的中断线程方式
public class ThreadInterruptDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Thread is running...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Thread interrupted during sleep");
Thread.currentThread().interrupt(); // 重新设置中断标志
}
}
System.out.println("Thread exiting...");
});
thread.start();
Thread.sleep(3000);
thread.interrupt(); // 中断线程
}
}
2.2.2 线程等待与通知
wait()/notify()机制是实现线程间通信的基础:
public class WaitNotifyDemo {
private static final Object lock = new Object();
private static boolean condition = false;
public static void main(String[] args) {
new Thread(() -> {
synchronized (lock) {
while (!condition) {
try {
System.out.println("Thread waiting...");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Thread notified, condition met");
}
}).start();
new Thread(() -> {
synchronized (lock) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
condition = true;
lock.notify();
System.out.println("Notified waiting thread");
}
}).start();
}
}
3. 线程同步与锁机制
3.1 synchronized关键字
synchronized是Java内置的同步机制,可以修饰方法或代码块:
// 同步方法
public synchronized void syncMethod() {
// 临界区代码
}
// 同步代码块
public void syncBlock() {
synchronized(this) {
// 临界区代码
}
}
synchronized的实现原理:
- 同步代码块使用monitorenter和monitorexit指令
- 同步方法使用ACC_SYNCHRONIZED标志
- 依赖于对象头中的Mark Word实现锁状态记录
3.2 ReentrantLock
ReentrantLock是JDK提供的更灵活的锁实现:
public class ReentrantLockDemo {
private final ReentrantLock lock = new ReentrantLock();
public void performAction() {
lock.lock(); // 获取锁
try {
// 临界区代码
} finally {
lock.unlock(); // 确保锁释放
}
}
}
ReentrantLock相比synchronized的优势:
- 可中断的锁获取
- 公平锁与非公平锁选择
- 多个条件变量支持
- 尝试获取锁(tryLock)
3.3 volatile关键字
volatile保证变量的可见性和有序性:
public class VolatileDemo {
private volatile boolean flag = false;
public void writer() {
flag = true; // 写操作
}
public void reader() {
if (flag) { // 读操作
// 基于flag的操作
}
}
}
volatile适用场景:
- 状态标志位
- 单例模式的双重检查锁定
- 独立观察(独立于程序状态的状态标志)
4. 线程池原理与实践
4.1 线程池核心参数
ThreadPoolExecutor的构造参数:
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 空闲线程存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 工作队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略
)
4.2 线程池工作流程
- 提交任务后,如果当前线程数 < corePoolSize,创建新线程执行任务
- 如果线程数 ≥ corePoolSize,将任务放入工作队列
- 如果队列已满且线程数 < maximumPoolSize,创建新线程执行任务
- 如果队列已满且线程数 ≥ maximumPoolSize,执行拒绝策略
4.3 常见线程池类型
- FixedThreadPool :固定大小线程池
ExecutorService fixedPool = Executors.newFixedThreadPool(5);
- CachedThreadPool :可缓存线程池
ExecutorService cachedPool = Executors.newCachedThreadPool();
- ScheduledThreadPool :定时任务线程池
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(3);
- SingleThreadExecutor :单线程池
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
注意:阿里巴巴Java开发手册建议手动创建ThreadPoolExecutor,避免使用Executors工厂方法,因为后者可能创建无界队列导致OOM。
4.4 线程池最佳实践
// 自定义线程池示例
public class CustomThreadPool {
private static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors();
private static final int MAX_POOL_SIZE = CORE_POOL_SIZE * 2;
private static final long KEEP_ALIVE_TIME = 1L;
private static final int QUEUE_CAPACITY = 100;
public static ExecutorService createCustomThreadPool() {
return new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.MINUTES,
new LinkedBlockingQueue<>(QUEUE_CAPACITY),
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
}
5. 高级并发工具类
5.1 CountDownLatch
允许一个或多个线程等待其他线程完成操作:
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
int threadCount = 5;
CountDownLatch latch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " working");
latch.countDown();
}).start();
}
latch.await();
System.out.println("All threads completed");
}
}
5.2 CyclicBarrier
让一组线程到达屏障时被阻塞,直到最后一个线程到达:
public class CyclicBarrierDemo {
public static void main(String[] args) {
int threadCount = 3;
CyclicBarrier barrier = new CyclicBarrier(threadCount,
() -> System.out.println("All threads reached barrier"));
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + " waiting");
barrier.await();
System.out.println(Thread.currentThread().getName() + " continued");
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}
5.3 Semaphore
控制同时访问特定资源的线程数量:
public class SemaphoreDemo {
public static void main(String[] args) {
int permits = 3;
Semaphore semaphore = new Semaphore(permits);
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " acquired permit");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
System.out.println(Thread.currentThread().getName() + " released permit");
}
}).start();
}
}
}
6. 线程安全与性能优化
6.1 线程安全集合
Java并发包提供了多种线程安全集合:
- ConcurrentHashMap :分段锁实现的线程安全HashMap
- CopyOnWriteArrayList :写时复制的线程安全List
- ConcurrentLinkedQueue :无锁实现的线程安全队列
- BlockingQueue 接口实现类:ArrayBlockingQueue、LinkedBlockingQueue等
// ConcurrentHashMap使用示例
public class ConcurrentHashMapDemo {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 线程安全的putIfAbsent
map.putIfAbsent("key", 1);
// 原子更新
map.compute("key", (k, v) -> v == null ? 1 : v + 1);
}
}
6.2 ThreadLocal原理与应用
ThreadLocal为每个线程提供独立的变量副本:
public class ThreadLocalDemo {
private static final ThreadLocal<SimpleDateFormat> dateFormatHolder =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
executor.execute(() -> {
SimpleDateFormat sdf = dateFormatHolder.get();
System.out.println(Thread.currentThread().getName() +
" using: " + sdf.format(new Date()));
});
}
executor.shutdown();
}
}
注意:使用ThreadLocal后必须调用remove()方法清理,避免内存泄漏,特别是在线程池环境中。
6.3 避免死锁的策略
- 锁顺序 :所有线程以相同顺序获取锁
- 锁超时 :尝试获取锁时设置超时时间
- 死锁检测 :定期检查死锁并恢复
- 避免嵌套锁 :尽量减少锁的嵌套使用
// 锁顺序示例
public class LockOrderingDemo {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void method1() {
synchronized(lock1) {
synchronized(lock2) {
// 临界区
}
}
}
public void method2() {
synchronized(lock1) { // 与method1相同的锁顺序
synchronized(lock2) {
// 临界区
}
}
}
}
7. Java内存模型与happens-before
7.1 Java内存模型(JMM)
JMM定义了线程如何与内存交互,主要关注:
- 原子性:基本类型读写是原子的(long/double除外)
- 可见性:一个线程的修改对其他线程可见
- 有序性:指令重排序的限制
7.2 happens-before原则
- 程序顺序规则 :同一线程中的操作按程序顺序执行
- 锁规则 :解锁操作先于后续的加锁操作
- volatile规则 :volatile写操作先于后续的读操作
- 线程启动规则 :Thread.start()先于线程中的任何操作
- 线程终止规则 :线程中的所有操作先于线程终止检测
- 中断规则 :interrupt()调用先于检测到中断
- 终结器规则 :对象构造先于finalize()方法
- 传递性 :A happens-before B,B happens-before C,则A happens-before C
// happens-before示例
public class HappensBeforeDemo {
private int x = 0;
private volatile boolean v = false;
public void writer() {
x = 42; // 1
v = true; // 2
}
public void reader() {
if (v) { // 3
System.out.println(x); // 保证看到42
}
}
}
8. 并发编程实践与性能调优
8.1 并发设计模式
- 生产者-消费者模式
public class ProducerConsumer {
private final BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(10);
class Producer implements Runnable {
public void run() {
try {
while (true) {
queue.put(1);
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Consumer implements Runnable {
public void run() {
try {
while (true) {
Integer item = queue.take();
System.out.println("Consumed: " + item);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
- 读写锁模式
public class ReadWriteLockDemo {
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
private Map<String, String> data = new HashMap<>();
public String get(String key) {
readLock.lock();
try {
return data.get(key);
} finally {
readLock.unlock();
}
}
public void put(String key, String value) {
writeLock.lock();
try {
data.put(key, value);
} finally {
writeLock.unlock();
}
}
}
8.2 性能优化建议
- 减少锁粒度 :缩小同步代码块范围
- 减少锁持有时间 :尽快释放锁
- 锁分离 :读写锁分离
- 无锁编程 :使用CAS操作
- 避免热点字段 :如AtomicLong可能成为性能瓶颈
- 合理设置线程池参数 :根据任务类型调整
// 锁粒度优化示例
public class LockGranularity {
private final Map<String, String> map1 = new HashMap<>();
private final Map<String, String> map2 = new HashMap<>();
private final Object lock1 = new Object();
private final Object lock2 = new Object();
// 细粒度锁
public void put1(String key, String value) {
synchronized(lock1) {
map1.put(key, value);
}
}
public void put2(String key, String value) {
synchronized(lock2) {
map2.put(key, value);
}
}
}
9. Java并发工具进阶
9.1 CompletableFuture
Java 8引入的异步编程工具:
public class CompletableFutureDemo {
public static void main(String[] args) throws Exception {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello";
}).thenApplyAsync(s -> s + " World")
.thenApply(String::toUpperCase);
System.out.println(future.get()); // 输出"HELLO WORLD"
}
}
9.2 Fork/Join框架
适用于分治算法的并行框架:
public class ForkJoinDemo {
static class FibonacciTask extends RecursiveTask<Long> {
final long n;
FibonacciTask(long n) { this.n = n; }
protected Long compute() {
if (n <= 1) return n;
FibonacciTask f1 = new FibonacciTask(n - 1);
f1.fork();
FibonacciTask f2 = new FibonacciTask(n - 2);
return f2.compute() + f1.join();
}
}
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool();
FibonacciTask task = new FibonacciTask(10);
System.out.println(pool.invoke(task)); // 输出55
}
}
10. 常见问题排查与调试
10.1 线程转储分析
获取线程转储的方法:
-
jstack命令:
jstack <pid> -
通过JMX:
ThreadMXBean.dumpAllThreads() -
发送信号:
kill -3 <pid>(Linux)
分析线程转储关注点:
- 死锁线程(标记为BLOCKED)
- 长时间运行的线程
- 大量等待同一锁的线程
- 线程状态分布
10.2 常见并发问题
- 死锁 :使用jstack检测
- 活锁 :线程不断改变状态但无法继续
- 饥饿 :低优先级线程长期得不到执行
- 竞态条件 :结果依赖于线程执行顺序
- 内存一致性错误 :违反happens-before规则
10.3 调试技巧
- 使用ThreadLocalRandom :替代Random,减少争用
- 避免在锁内调用外部方法 :防止死锁
- 使用并发集合 :替代同步包装类
-
合理设置线程池大小
:
- CPU密集型:CPU核数+1
- IO密集型:CPU核数*2
// 线程池大小计算示例
public class PoolSizeCalculator {
public static int getIdealThreadPoolSize() {
int cores = Runtime.getRuntime().availableProcessors();
// IO密集型任务
return (int)(cores / (1 - 0.9)); // 假设阻塞系数为0.9
}
}
11. Java并发新特性
11.1 Java虚拟线程(Project Loom)
Java 19引入的轻量级线程:
// 虚拟线程使用示例
public class VirtualThreadDemo {
public static void main(String[] args) throws Exception {
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 10_000; i++) {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1));
return "Done";
});
}
}
}
}
虚拟线程特点:
- 由JVM管理,非操作系统线程
- 创建成本极低,可创建数百万个
- 阻塞操作不会占用系统线程
11.2 结构化并发(Java 21)
简化多线程编程模型:
// 结构化并发示例
public class StructuredConcurrencyDemo {
public static void main(String[] args) {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> user = scope.fork(() -> findUser());
Future<Integer> order = scope.fork(() -> fetchOrder());
scope.join(); // 等待所有任务
scope.throwIfFailed(); // 检查异常
System.out.println("User: " + user.resultNow() +
", Order: " + order.resultNow());
} catch (Exception e) {
e.printStackTrace();
}
}
}
12. 并发编程最佳实践
- 优先使用高级并发工具 :如并发集合、线程池
- 避免过早优化 :先保证正确性,再考虑性能
- 编写无状态对象 :减少同步需求
- 使用不可变对象 :简化线程安全设计
- 文档化线程安全策略 :明确类的线程安全级别
- 避免过度同步 :缩小同步范围
- 考虑替代方案 :如消息传递、Actor模型
- 全面测试并发代码 :包括压力测试和边界测试
// 不可变对象示例
public final class ImmutablePoint {
private final int x;
private final int y;
public ImmutablePoint(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() { return x; }
public int getY() { return y; }
public ImmutablePoint move(int dx, int dy) {
return new ImmutablePoint(x + dx, y + dy);
}
}
13. 常见面试问题解析
13.1 synchronized与ReentrantLock区别
| 特性 | synchronized | ReentrantLock |
|---|---|---|
| 实现机制 | JVM内置实现 | JDK代码实现 |
| 锁获取方式 | 自动获取释放 | 需要手动lock/unlock |
| 可中断性 | 不支持 | 支持lockInterruptibly() |
| 公平锁 | 非公平 | 可选择公平/非公平 |
| 条件变量 | 单个等待队列 | 支持多个Condition |
| 性能 | JDK6后优化,性能接近 | 提供更丰富的功能 |
13.2 volatile与synchronized区别
| 特性 | volatile | synchronized |
|---|---|---|
| 作用范围 | 变量级别 | 变量、方法、代码块级别 |
| 原子性 | 不保证复合操作原子性 | 保证操作的原子性 |
| 可见性 | 保证可见性 | 保证可见性 |
| 有序性 | 禁止指令重排序 | 保证有序性 |
| 线程阻塞 | 不会导致线程阻塞 | 可能导致线程阻塞 |
| 适用场景 | 状态标志、双重检查锁定 | 需要原子性操作的场景 |
13.3 线程池参数配置建议
-
CPU密集型任务 :
- corePoolSize = CPU核数 + 1
- maximumPoolSize = corePoolSize
- 使用有界队列防止资源耗尽
-
IO密集型任务 :
- corePoolSize = CPU核数 × 2
- maximumPoolSize = corePoolSize × 2
- 使用较大的队列缓冲
-
混合型任务 :
- 将任务分类,使用不同的线程池处理
- 监控调整参数达到最佳性能
// 动态调整线程池参数示例
public class DynamicThreadPool extends ThreadPoolExecutor {
public DynamicThreadPool(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
// 动态调整核心线程数
public void setCorePoolSize(int corePoolSize) {
super.setCorePoolSize(corePoolSize);
}
// 动态调整最大线程数
public void setMaximumPoolSize(int maximumPoolSize) {
super.setMaximumPoolSize(maximumPoolSize);
}
}
14. 并发编程的未来趋势
- 响应式编程 :如Reactor、RxJava
- 协程/虚拟线程 :轻量级并发模型
- 无锁数据结构 :提高并发性能
- 函数式并发 :不可变数据+纯函数
- 分布式并发 :跨JVM的协调机制
- 硬件感知并发 :利用NUMA架构特性
// 响应式编程示例
public class ReactiveExample {
public static void main(String[] args) {
Flux.range(1, 10)
.parallel()
.runOn(Schedulers.parallel())
.map(i -> i * 2)
.subscribe(System.out::println);
}
}
15. 实战经验分享
在实际项目中应用多线程时,我总结了以下几点经验:
- 明确并发需求 :不是所有场景都需要并发,评估真正需要并发的部分
- 优先使用现有工具 :如并发集合、线程池,避免重复造轮子
- 保持简单 :复杂的并发设计难以维护和调试
- 全面测试 :包括功能测试、性能测试和压力测试
- 监控与调优 :使用JMX、Profiler等工具持续监控
- 渐进式优化 :先保证正确性,再逐步优化性能
- 文档与注释 :详细记录线程安全策略和并发设计
// 实际项目中的线程安全计数器
public class SafeCounter {
private final AtomicLong counter = new AtomicLong();
private final LongAdder fastCounter = new LongAdder();
// 精确计数
public long incrementAndGet() {
return counter.incrementAndGet();
}
// 高性能计数
public void fastIncrement() {
fastCounter.increment();
}
public long fastSum() {
return fastCounter.sum();
}
}
16. 性能对比与基准测试
不同并发工具的性能差异:
| 场景 | 实现方式 | 吞吐量(ops/ms) | 备注 |
|---|---|---|---|
| 计数器 | synchronized | 1,200 | 高争用时性能下降 |
| 计数器 | AtomicLong | 5,800 | CAS实现 |
| 计数器 | LongAdder | 12,400 | 低争用下最优 |
| Map操作 | Hashtable | 850 | 全表锁 |
| Map操作 | Collections.synchronizedMap | 920 | 包装器模式 |
| Map操作 | ConcurrentHashMap | 7,300 | 分段锁 |
基准测试建议:使用JMH(Java Microbenchmark Harness)进行可靠的微基准测试,避免JVM优化带来的误差。
// JMH基准测试示例
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class CounterBenchmark {
@State(Scope.Thread)
public static class MyState {
public final AtomicLong atomicCounter = new AtomicLong();
public final LongAdder adderCounter = new LongAdder();
}
@Benchmark
public long testAtomicIncrement(MyState state) {
return state.atomicCounter.incrementAndGet();
}
@Benchmark
public void testAdderIncrement(MyState state) {
state.adderCounter.increment();
}
}
17. 并发设计模式进阶
17.1 Thread-Per-Message模式
为每个请求创建独立线程处理:
public class ThreadPerMessageDemo {
public static void main(String[] args) {
Host host = new Host();
host.request(10, 'A');
host.request(20, 'B');
}
static class Host {
private final ExecutorService executor =
Executors.newCachedThreadPool();
public void request(int count, char c) {
executor.execute(() -> {
for (int i = 0; i < count; i++) {
System.out.print(c);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
17.2 Worker Thread模式
使用工作线程池处理任务:
public class WorkerThreadDemo {
public static void main(String[] args) {
Channel channel = new Channel(5);
channel.startWorkers();
new ClientThread("Alice", channel).start();
new ClientThread("Bobby", channel).start();
}
static class Channel {
private final BlockingQueue<Request> queue;
private final Thread[] threads;
public Channel(int threads) {
this.queue = new LinkedBlockingQueue<>();
this.threads = new Thread[threads];
}
public void startWorkers() {
for (int i = 0; i < threads.length; i++) {
threads[i] = new WorkerThread("Worker-" + i, this);
threads[i].start();
}
}
public void putRequest(Request request) {
try {
queue.put(request);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public Request takeRequest() {
try {
return queue.take();
} catch (InterruptedException e) {
return null;
}
}
}
}
18. 并发调试工具推荐
- VisualVM :监控线程状态、内存使用
- JConsole :JMX监控工具
- JProfiler :商业性能分析工具
- YourKit :商业Java Profiler
- Arthas :阿里开源的Java诊断工具
- jstack :生成线程转储
- jcmd :多功能命令行工具
使用jstack分析死锁示例:
# 查找Java进程ID
jps
# 生成线程转储
jstack <pid> > thread_dump.txt
# 分析死锁
grep -A 10 "deadlock" thread_dump.txt
19. 跨语言并发模型比较
| 语言 | 主要并发模型 | 特点 |
|---|---|---|
| Java | 线程+锁 | 成熟、复杂、JVM优化 |
| Go | Goroutine+CSP | 轻量级、内置调度器 |
| Erlang | Actor模型 | 容错性强、热代码升级 |
| Rust | 所有权+无数据竞争 | 编译时保证线程安全 |
| C++ | 线程+原子操作+各种库 | 灵活、性能高、复杂度高 |
| JavaScript | 事件循环+Promise/async-await | 单线程异步、WebWorker多线程 |
20. 持续学习资源推荐
-
书籍 :
- 《Java并发编程实战》
- 《并发编程的艺术》
- 《Java并发编程之美》
-
在线课程 :
- Coursera: Parallel Programming in Java
- Udemy: Java Multithreading, Concurrency & Performance Optimization
-
开源项目 :
- Netty
- RxJava
- Akka
-
博客与社区 :
- InfoQ并发专栏
- 美团技术团队博客
- Stack Overflow并发标签
-
实践平台 :
- LeetCode多线程题目
- Codewars并发kata
- 自己实现小型并发框架

355

被折叠的 条评论
为什么被折叠?



