☰
Java多线程与高并发,看这一篇就够了
2026/10/3 16:46:16 网站建设 项目流程

线程状态不是背的,是看的

NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED,这六个状态背下来不难,难的是知道线程卡在哪儿。线上CPU飙高,jstack打出来的线程栈里,BLOCKED是在等锁,WAITING是在等通知,TIMED_WAITING多半在sleep或者带超时的wait。看不懂线程状态,排查问题就是盲人摸象。一个线程池满了,任务在队列里排着,线程在等锁,锁被另一个慢SQL占着,环环相扣,你得会顺藤摸瓜。

线程池:别再用Executors了

Executors.newFixedThreadPool和newCachedThreadPool,阿里规范明令禁止。前者队列无界,任务堆积到OOM;后者线程数无上限,请求一多就创建大量线程,直接拖垮系统。线程池必须手动new,七个参数一个一个想清楚。核心线程数看业务是CPU密集还是IO密集,队列用有界,拒绝策略选CallerRunsPolicy让调用方跑,自然形成背压。别嫌麻烦,线上事故都是从图省事开始的。

锁:从synchronized到ReentrantLock

synchronized是JVM内置锁,自动释放,但不可中断、不超时、不公平。ReentrantLock手动释放,可中断、可超时、可公平,还能多个条件变量。选哪个不看性能,看场景。简单同步用synchronized,复杂协调用ReentrantLock。但记住,锁的粒度越小越好,锁的时间越短越好。把耗时的IO操作放在锁外面,别让一个慢请求拖死所有线程。

JMM与volatile:看不见的坑最深

Java内存模型规定,每个线程有自己的工作内存,共享变量从主内存拷贝。一个线程改了,另一个线程可能看不见。volatile保证可见性和禁止指令重排,但不保证原子性。i++用volatile修饰照样丢数据,因为读-改-写不是原子操作。要原子性,用AtomicInteger或者加锁。双重检查锁单例里,instance必须加volatile,否则可能拿到半初始化对象。这个坑,面试必问,线上必踩。

CAS:无锁编程的基石

compareAndSwap,比较并交换,CPU原语,原子操作。AtomicInteger、AtomicReference底层都是CAS。CAS避免了锁的开销,但带来了ABA问题和自旋消耗。ABA问题用版本号解决,AtomicStampedReference就是干这个的。自旋消耗在竞争激烈时反而比锁慢,所以LongAdder出现了,分段累加,最后汇总,高并发下比AtomicLong快得多。没有银弹,只有权衡。

高并发设计:分流、限流、异步

高并发的核心不是让一个接口扛住一万并发,是把一万并发分散到十个接口、十台机器、十个线程上。分流靠负载均衡,限流靠令牌桶和漏桶,异步靠消息队列和CompletableFuture。能异步的别同步,能并行的别串行,能缓存的别查库。一个请求进来,先看缓存,缓存没有再查库,查库用连接池,连接池大小要跟数据库承受能力匹配。每一步都算清楚,并发才上得去。

多线程与高并发,说到底是对资源的精细调度。线程是资源,锁是资源,数据库连接是资源,CPU时间片也是资源。把合适的任务放到合适的线程上,用合适的锁保护合适的临界区,在合适的时机释放资源。这三点做到了,高并发就不是玄学。别指望一篇文章解决所有问题,但这一篇,够你搭起一个不塌的架子。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询