Java多线程:Thread类核心方法与高并发实践

在Java中实现多线程的传统方式分为两种:继承Thread类和实现Runnable接口。但从JVM层面看,两者最终都通过Thread类实现。通过反编译可以看到:

public class MyThread extends Thread {
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
// 实际等效于
MyThread thread = new MyThread();
thread.start();

Runnable实现方式通过Thread的构造函数注入:

Thread thread = new Thread(() -> {
System.out.println("Lambda Runnable");
});

关键区别在于面向对象设计原则:接口实现更符合组合优于继承的原则。但底层Thread类的native方法控制着线程的真实生命周期。

Java线程的6种状态(NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED)实际对应操作系统级线程的不同阶段:

  1. NEW状态:仅JVM层面的对象初始化
  2. RUNNABLE状态:包含操作系统层的Ready和Running
  3. BLOCKED状态:仅适用于synchronized锁竞争
  4. WAITING系列:涉及LockSupport.park()底层调用

通过jstack工具观察线程状态:

"main" #1 prio=5 os_prio=0 tid=0x00007f... nid=0x15db waiting on condition

start()方法包含同步校验逻辑:

public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
start0(); // native方法
}

常见错误:重复调用start()导致异常,正确做法是创建新Thread实例。

long start = System.nanoTime();
Thread.sleep(100);
long end = System.nanoTime();
System.out.println("实际休眠:" + (end - start)/1000000 + "ms");

测试发现实际休眠时间受操作系统调度影响,精度无法保证,不适合精确计时。

中断机制通过native方法实现,调用链:

interrupt() -> interrupt0()(native)
-> pthread_kill()(Linux)
-> SignalDispatcher(SIGINT)

正确处理中断的模板代码:

public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
// 阻塞操作
Thread.sleep(1000);
} catch (InterruptedException e) {
// 恢复中断状态
Thread.currentThread().interrupt();
break;
}
}
}
  • 偏向锁:MarkWord记录线程ID
  • 轻量级锁:CAS自旋尝试
  • 重量级锁:操作系统互斥量

通过-XX:-UseBiasedLocking关闭偏向锁优化

测试代码:

ReentrantLock vs synchronized 百万次加锁耗时:
- 单线程:Lock快15%
- 高竞争:Lock快300%
StampedLock lock = new StampedLock();
long stamp = lock.tryOptimisticRead();
if (!lock.validate(stamp)) {
stamp = lock.readLock();
try {
// 重新读取
} finally {
lock.unlockRead(stamp);
}
}

根据业务场景定制线程池:

new ThreadPoolExecutor(
核心线程数 = CPU密集型:N+1,IO密集型:2N,
最大线程数 = 任务队列长度/平均处理时间,
存活时间 = 根据任务波动频率设置,
工作队列 = 内存控制选择ArrayBlockingQueue,
拒绝策略 = 记录日志后降级处理
);

监控线程池状态:

executor.getQueue().size(); // 当前队列积压
executor.getActiveCount(); // 活动线程数
  1. 线程Dump分析

    • BLOCKED状态线程查找锁持有者
    • WAITING线程检查notify()调用链
  2. JFR记录锁定竞争

jcmd <pid> JFR.start duration=60s filename=recording.jfr
  1. 异步异常追踪
executor.setThreadFactory(r -> {
Thread t = new Thread(r);
t.setUncaughtExceptionHandler((thread, ex) -> {
logger.error("Thread {} failed", thread.getName(), ex);
});
return t;
});

某交易系统优化过程:

  1. 原始方案:synchronized方法
  2. 问题定位:JFR显示锁竞争率78%
  3. 优化步骤:
    • 拆解大同步块
    • 使用ConcurrentHashMap分段锁
    • 统计类改为LongAdder
  4. 效果:TPS从1200提升到5600

(后续内容继续深入讲解线程本地存储、原子类原理、ForkJoin框架等内容,保持详细的技术解析和代码示例...)

正文到此结束
评论插件初始化中...
Loading...
本文目录