Java 线程架构与同步:从 CPU 到 JVM
Java 代码编译成字节码,由 JVM 转换为处理器可执行的机器指令。每颗 CPU 核心按顺序执行指令:寄存器中的位移操作等简单指令仅需一个时钟周期完成。寄存器是超高速存储单元,用于存放数字、地址和数据。
现代处理器采用超标量架构。超线程技术让单个硬件线程每周期执行 2–6 条指令,通过快速上下文切换,在每颗核心上模拟多个逻辑线程。
同时运行的线程数受核心数量限制。线程共享堆内存存储对象,每个线程有独立的栈来保存局部变量和对象引用。
竞态条件与内存结构
竞态条件发生在多个线程同时读写同一堆对象时,结果不可预测,取决于读-改-写操作的顺序。
代码在本地无负载时往往运行正常,但在生产环境的多线程负载下,冲突会不定期出现。操作系统进程分配共享内存;其中的线程是轻量级执行单元,竞争资源。
同步机制:wait/notify 和监视器
每个 Java 对象内置一个监视器(锁)。synchronized 块获取对象的监视器,确保:
- 互斥性:仅一个线程执行块内代码。
- 可见性:退出块后变更对其他线程可见(结合
volatile支持)。
监视器包含:
- 入口集:等待获取的线程队列。
- 等待集:处于等待状态的线程。
wait()、notify() 和 notifyAll() 仅在同一对象的 synchronized 块内有效,否则抛出 IllegalMonitorStateException。
wait():将线程移入等待集。notify():唤醒一个随机线程(有唤醒丢失风险)。notifyAll():唤醒所有线程(推荐做法)。
静态 synchronized 方法锁定类监视器(Class),不与实例方法(this)冲突。
高级锁机制:ReentrantLock 和 Semaphore
需要更多控制时,使用 java.util.concurrent.locks.ReentrantLock:
Lock lock = new ReentrantLock();
lock.lock();
try {
// 关键区
} finally {
lock.unlock();
}
关键方法:
tryLock():非阻塞获取(失败返回 false)。tryLock(timeout, unit):带超时的等待。lockInterruptibly():可中断获取。new ReentrantLock(true):公平锁(FIFO 顺序,稍慢)。
Semaphore 限制并发访问:
Semaphore sem = new Semaphore(3); // 3 个许可
sem.acquire(); // 获取
sem.release(); // 释放
多线程陷阱:死锁与活锁
死锁:循环锁依赖。线程 A 持有锁1 等待锁2;线程 B 反之。系统卡死。
避免方法:
- 固定锁顺序。
- 使用超时。
- 最小化嵌套锁。
活锁:线程忙碌但无进展。例如:两个线程礼貌地互相让出资源,形成循环,CPU 飙升却无前进一步。
线程中的同步与异步
同步方法在 I/O 操作(如数据库查询)时阻塞线程:线程空闲等待响应。
异步使用 CompletableFuture——延迟结果容器(待定、完成或失败)。
操作链:
thenApply():转换结果。thenCompose():与其他 Future 组合。thenAccept():消费无返回值。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "result")
.thenApply(s -> s.toUpperCase())
.thenAccept(System.out::println);
这释放线程处理其他任务,提升多线程环境吞吐量。
关键要点
- 每核心运行一个硬件线程;超线程模拟多个。
- 竞态条件源于共享堆;同步确保互斥与可见性。
- 优先
notifyAll()避免唤醒丢失。 - ReentrantLock 扩展
synchronized,支持超时、中断与公平性。 - CompletableFuture 实现无阻塞异步流水线。
— Editorial Team
暂无评论。