Java进程与线程及高并发实践指南
进程与线程的本质差异
(1)资源分配维度:
每个进程拥有独立的堆内存空间(JVM实例)、文件描述符和系统资源。例如在Java中通过ProcessBuilder
创建子进程时,操作系统会分配约1MB的栈空间。而线程共享进程资源,仅保留独立栈(默认1MB,可通过-Xss
调整)和程序计数器。
(2)执行调度成本:
上下文切换时,进程需要切换页表、刷新TLB,耗时约1-10微秒;线程切换仅需保存寄存器,耗时约0.1-1微秒。通过perf stat
工具可观测到具体差异。
(3)通信机制对比:
进程间通信(IPC)常用方式:
// 命名管道示例
Path fifo = Paths.get("/tmp/myfifo");
Files.createNamedPipe(fifo, NamedPipeOptions.READ_WRITE);
// 共享内存示例
FileChannel channel = FileChannel.open(shmFile, READ, WRITE, CREATE, DELETE_ON_CLOSE);
MappedByteBuffer buffer = channel.map(READ_WRITE, 0, 1024);
线程间通信直接通过共享内存:
// 使用volatile保证可见性
volatile boolean flag = false;
// 使用Atomic原子类
AtomicInteger counter = new AtomicInteger(0);
线程实现深度解析
(1)JVM线程模型演进:
- Green Thread(JDK 1.1):完全用户级线程,M:N映射
- Native Thread(JDK 1.2起):1:1内核线程映射
- Virtual Thread(Loom项目):M:N混合模型
(2)创建方式对比:
// 方法1:继承Thread(不推荐)
class MyThread extends Thread {
public void run() {
// 实现逻辑
}
}
// 方法2:实现Runnable(推荐)
Runnable task = () -> {
// 线程执行体
};
new Thread(task).start();
// 方法3:Callable + Future
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(() -> {
return 42;
});
(3)线程优先级误区:
通过setPriority(1-10)
设置的优先级在Linux中被忽略,Windows中部分有效。建议使用CompletableFuture
或ManagedTask
进行精细控制。
线程状态转换全流程
stateDiagram-v2
[*] --> NEW
NEW --> RUNNABLE: start()
RUNNABLE --> BLOCKED: 等待synchronized锁
RUNNABLE --> WAITING: wait()/join()
RUNNABLE --> TIMED_WAITING: sleep(n)
BLOCKED --> RUNNABLE: 获取锁
WAITING --> RUNNABLE: notify()/notifyAll()
TIMED_WAITING --> RUNNABLE: 超时结束
RUNNABLE --> TERMINATED: run()结束
通过jstack
工具可查看实际线程状态:
$ jstack <pid> | grep 'java.lang.Thread.State'
线程池核心技术参数
(1)核心参数关系:
ThreadPoolExecutor(
int corePoolSize, // 常驻线程数
int maximumPoolSize, // 最大扩容数
long keepAliveTime, // 空闲线程存活时间
TimeUnit unit,
BlockingQueue<Runnable> workQueue, // 任务队列
RejectedExecutionHandler handler // 拒绝策略
)
(2)队列类型对比表: | 队列类型 | 特性 | 适用场景 | |-----------------------|----------------------------|---------------------| | SynchronousQueue | 无容量,直接传递 | CachedThreadPool | | LinkedBlockingQueue | 无界队列(默认Integer.MAX_VALUE) | FixedThreadPool | | ArrayBlockingQueue | 有界队列 | 自定义线程池 | | PriorityBlockingQueue | 带优先级队列 | 任务需要优先级排序 | | DelayedWorkQueue | 延迟任务队列 | ScheduledThreadPool |
(3)拒绝策略源码分析:
// 默认四种策略
public static class AbortPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException();
}
}
// 自定义策略示例
new ThreadPoolExecutor.CallerRunsPolicy() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
if (!executor.isShutdown()) {
r.run(); // 由提交线程直接执行
}
}
};
同步机制的实现原理
(1)synchronized底层演进:
- JDK 1.6前:直接使用操作系统互斥锁
- 偏向锁(Biased Locking):无竞争时直接进入
- 轻量级锁(Thin Locking):CAS自旋尝试
- 重量级锁:最终回退到操作系统互斥量
查看锁升级过程:
$ java -XX:+PrintFlagsFinal | grep BiasedLocking
(2)AQS(AbstractQueuedSynchronizer)原理:
ReentrantLock内部通过CLH队列实现:
// 简化版AQS获取锁逻辑
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 处理重入逻辑...
}
(3)内存屏障实现:
volatile变量写操作插入StoreStore + StoreLoad屏障:
; x86实现(内存屏障类型)
lock addl $0x0,(%rsp)
并发工具高级用法
(1)CountDownLatch与CyclicBarrier对比:
// CountDownLatch(一次性)
CountDownLatch latch = new CountDownLatch(3);
latch.countDown();
latch.await();
// CyclicBarrier(可重复使用)
CyclicBarrier barrier = new CyclicBarrier(3, () ->
System.out.println("All parties arrived"));
barrier.await();
(2)CompletableFuture组合操作:
CompletableFuture.supplyAsync(() -> fetchData())
.thenApplyAsync(data -> process(data))
.exceptionally(ex -> handleError(ex))
.thenAcceptAsync(result -> saveResult(result))
.join();
(3)StampedLock优化读场景:
StampedLock lock = new StampedLock();
// 乐观读
long stamp = lock.tryOptimisticRead();
if (!lock.validate(stamp)) {
stamp = lock.readLock();
try {
// 重新读取
} finally {
lock.unlockRead(stamp);
}
}
虚拟线程实践指南
(1)创建方式对比:
// 平台线程
Thread.ofPlatform().name("worker-", 0).start(task);
// 虚拟线程
Thread.ofVirtual().name("vt-", 0).start(task);
// 使用ExecutorService
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(task1);
executor.submit(task2);
}
(2)性能测试数据: | 线程类型 | 内存占用 | 创建时间 | 上下文切换成本 | |---------|------|-------|---------| | 平台线程 | 1MB | ~2ms | 高 | | 虚拟线程 | ~4KB | ~0.1ms | 极低 |
(3)注意事项:
- 避免使用线程局部变量(ThreadLocal)
- 不要包装在池中(本身就是轻量级)
- 同步代码块仍会绑定到载体线程
生产环境问题排查
(1)死锁检测:
$ jstack <pid> | grep -A 10 deadlock
(2)线程泄漏检测:
// 使用ThreadMXBean
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long[] threadIds = bean.findDeadlockedThreads();
if (threadIds != null) {
ThreadInfo[] infos = bean.getThreadInfo(threadIds);
// 分析线程堆栈
}
(3)内存可见性问题诊断: 使用JFR(Java Flight Recorder)记录内存屏障事件:
$ jcmd <pid> JFR.start duration=60s filename=recording.jfr