JUC并发编程入门:从线程状态到Lock锁,一文吃透生产者消费者

简介: JUC并发编程是Java面试常考点。本文用学习笔记视角,理清线程状态、Lock与Synchronized的区别,手写生产者消费者并解决虚假唤醒。

大家好,我是晚安code。

JUC并发编程这门课几乎是 Java 后端面试的必考点——从「线程有几种状态」到「手写生产者消费者」,一问一个准。这篇就把我踩过的坑和整理好的思路一次性给你:线程状态、Lock 与 Synchronized 的区别、还有那个让无数人翻车的虚假唤醒。收藏一下,面试前翻出来救急。

一、JUC 是什么:并发编程的「工具包」

JUC 不是一门新语言,它是 Java 官方写给并发编程的标准答案,藏在 java.util.concurrent 这个包里。

JUC(java.util.concurrent):Java 官方提供的并发编程工具包,把锁、线程池、并发集合都收在了这一个包下。你可以理解为「Java 并发编程的百宝箱」。

自己写业务时,用普通 Thread 开线程效率并不高。传统 Runnable 接口没有返回值,回调结果全靠共享变量,又麻烦又容易出并发问题;Callable 接口能返回结果,配合 Future 才能拿到线程的返回值。JUC 就是把这一套高效写法给做成了标准库。

二、线程与进程:并发和并行别搞混

并发和并行是 JUC 学习路上第一个绊脚石,分不清它,后面全是糊涂账。

先说进程和线程:进程是一个程序的集合,比如 QQ.exe 就是一个进程,一个进程至少包含一个线程。线程是进程里的执行单元,比如你用 Typora 打字的同时它还在自动保存——写字和保存就是两个线程在干活。Java 程序默认开两个线程:main 主线程和 GC 垃圾回收线程。

有个冷知识:Java 本身是开不了线程的。Thread.start() 底层调用的是 native start0(),这是本地方法,由底层的 C++ 操作操作系统去创建线程,Java 只负责把请求递下去。

并发:多个线程在同一段时间内交替执行同一个资源,单核 CPU 也能模拟出来。可以理解为「一条路,多辆车轮流过」。

并行:多个线程在多个 CPU 核上同时执行,真正的同时干活。可以理解为「多条路,车同时开」。

并发编程的本质就一句话:充分利用 CPU 资源。通过 Runtime.getRuntime().availableProcessors() 可以拿到 CPU 核数,写线程池时区分 CPU 密集型和 IO 密集型的核心线程数就用它。

并发靠 CPU 快速交替,并行靠多核同时跑

三、线程的六种状态 + wait/sleep 区别

线程状态的管理,本质是 JVM 搭好的一套流转规则,记住六种状态,面试第一问基本就稳了。

Java 线程一共有六种状态,定义在 Thread.State 枚举里:

状态 含义 进入方式
NEW 新生,线程刚创建没 start new Thread()
RUNNABLE 运行中,等待 CPU 调度 start()
BLOCKED 阻塞,竞争锁失败排队 进入同步代码块
WAITING 等待,一直等被唤醒 wait()join()
TIMED_WAITING 超时等待,到点自己醒 sleep()wait(毫秒)
TERMINATED 终止,run() 执行完 正常结束

我用一张图把它串起来,面试时照着这个思路说就行:

线程状态流转图:JUC并发编程中线程的六种状态及切换条件

wait 和 sleep 是面试最爱问的一对兄弟,因为它俩长得像,本质上完全不一样。

我整理成一张表

对比项 wait sleep
来自哪个类 Object Thread
是否释放锁 释放 不释放
使用范围 必须在同步代码块中 任何地方都能用
是否必须捕获异常 不需要 必须捕获

企业里写休眠推荐用 TimeUnit 工具类,比裸写 Thread.sleep 语义清晰得多:

TimeUnit.DAYS.sleep(1);    // 睡 1 天
TimeUnit.SECONDS.sleep(2); // 睡 2 秒

四、Lock 锁:从 synchronized 到 ReentrantLock

Lock 是 JUC 里最该先掌握的锁,它把 synchronized 的短板全补上了。先看传统写法。

传统 synchronized 解决并发问题,本质就两个字:队列 + 。多个线程同时卖票,不加锁就会超卖:

class Ticket {
   
    private int number = 50;
    public synchronized void sale() {
      // synchronized 本质:排队 + 加锁
        if (number > 0) {
   
            System.out.println(Thread.currentThread().getName()
                + " 卖出了 " + (number--) + " 票,剩余 " + number);
        }
    }
}

synchronized 用起来省心,但它有几个短板:拿不到锁状态、线程只能一直等、锁非公平、不可中断。JUC 的 Lock 接口就是来解决这些问题的。

Lock:JUC 提供的锁接口,最常用的实现是 ReentrantLock。你可以把它想成一把「手动挡」的锁,加锁解锁都得自己来。

class Ticket2 {
   
    private int number = 50;
    Lock lock = new ReentrantLock();  // 1. 建锁

    public void sale() {
   
        lock.lock();                  // 2. 加锁
        try {
   
            if (number > 0) {
    /* 卖票业务 */ }
        } finally {
   
            lock.unlock();            // 3. 解锁,不写就是死锁
        }
    }
}

lock 三部曲:① new ReentrantLock() 建锁 → ② lock.lock() 加锁 → ③ finallylock.unlock() 解锁。第三步最关键,忘了写整个程序直接卡死。

ReentrantLock 还分公平锁和非公平锁,默认是非公平:

公平锁:先来后到,谁先排队谁先拿到锁。可以理解为食堂打饭排好队,不乱。

非公平锁:允许插队,刚释放的锁可能被后来的线程抢走(默认)。可以理解为排队时突然有人插队。

构造时传 true 就是公平锁:new ReentrantLock(true);不传参数默认非公平:new ReentrantLock()

synchronized 和 Lock 怎么选,一张表说清楚:

对比项 synchronized Lock
判断锁状态 做不到 tryLock() 能判断
释放锁 自动释放 必须手动,finally 里 unlock
等待方式 线程一直等 不会一直等,可超时
公平性 只能非公平 可设置公平/非公平
适用场景 少量同步代码 大量同步代码

默认非公平锁能插队,公平锁要排队,吞吐量各有利弊

五、生产者消费者问题:从 wait/notify 到 Condition

生产者消费者问题是 JUC 面试的必考题,和单例模式、排序算法、死锁并称「面试四件套」。考的不是你会不会写,而是你懂不懂等待-通知这套机制。

经典场景:一个数据类,increment 加 1、decrement 减 1,生产线程 A 加了要通知消费者 B 来减。synchronized 版本的套路是四步:判断 → 等待 → 业务 → 通知

public synchronized void increment() throws InterruptedException {
   
    while (number != 0) {
         // 1. 判断:number 不是 0 就等
        this.wait();           // 2. 等待
    }
    number++;                  // 3. 业务:加 1
    this.notifyAll();          // 4. 通知:唤醒其他线程
}

我第一次学习时写这段代码时,只有 A、B 两个线程跑得好好的,结果突发奇想我换成 A/B/C/D 四个线程,当场就翻车了——数据直接变成负数。

原因就是我用了 if 判断,这就是传说中的虚假唤醒

可能有人会问:什么情况会被虚假唤醒?

当有多个线程同时 wait 在同一个条件上时,某个线程可能没收到通知、没被中断、也没超时,却被莫名唤醒。Java 官方文档明确建议:wait 必须放在循环里(while 判断),等条件真正满足再继续。把 if 改成 while 就彻底解决——每次醒来重新判断一次,不满足就继续等。

虚假唤醒(Spurious Wakeup):线程没收到明确通知却被意外唤醒的现象。可以理解为「闹钟还没响,你却提前醒了」。

JDK 官方 javadoc 明确要求 wait 要写在循环里防虚假唤醒

if 判断一次容易翻车,while 醒来再确认一遍才安全

而 JUC 版的生产者消费者,把 wait/notify 换成了 Lock + Condition,套路一模一样,只是换了 API:

Condition:和 Lock 配套的等待/通知工具,把 wait/notify 从 Object 搬到了锁上。可以理解为锁的「对讲机」,用它喊话唤醒线程。

class Data {
   
    private int number = 0;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public void increment() throws InterruptedException {
   
        lock.lock();
        try {
   
            while (number != 0) {
   
                condition.await();      // 等待(替代 wait)
            }
            number++;
            condition.signalAll();      // 通知(替代 notifyAll)
        } finally {
   
            lock.unlock();
        }
    }
}

整个流程还是「判断 → 等待 → 业务 → 通知」四步,一张图看清:

生产者消费者流程:判断等待业务通知的循环

JUC 版的好处是:Condition 可以创建多个,实现精准唤醒——比如唤醒「加 1 的」和唤醒「减 1 的」分开,比 notifyAll 一把梭精准得多,这也是 JUC 里 ArrayBlockingQueue 等并发容器底层正在用的思路。


我把整个 JUC并发编程学习笔记按这条主线整理完了:并发/并行 → 线程状态 → wait/sleep → Lock → 生产者消费者。这篇算 JUC 的地基,

我是晚安code,持续分享编程干货。觉得有用的话记得点赞收藏和关注~也欢迎在评论区聊聊:你学 JUC 时踩过哪些并发坑?wait 和 sleep 第一次分清楚了吗?

目录
相关文章
|
8天前
|
云安全 人工智能 运维
阿里云联动百位企业安全专家,共识Agent防御最佳实践
当Agent成为新员工,你的安全边界在哪里?
1929 8
阿里云联动百位企业安全专家,共识Agent防御最佳实践
|
2天前
|
编解码 人工智能 安全
2核4G/4核8G/8核16G阿里云服务器如何选择实例?经济型e、通用算力型u2i与计算型c9i选哪个?
本文介绍了阿里云2核4G、4核8G、8核16G三档主流配置下经济型e、通用算力型u2i和计算型c9i三种实例的最新活动价格与适用场景。同配置下三者价差显著,以2核4G为例,经济型e低至599.93元/年,计算型c9i则高达1742.08元/年。文章详细解析了各实例的性能定位:经济型e适合轻负载入门场景,u2i兼顾稳定算力与性价比,c9i凭借第9代至强处理器与芯片级安全能力支撑高性能业务。同时提示用户可叠加满减优惠券享受折上折,建议根据业务负载与预算综合决策。
501 111
|
6天前
|
存储 人工智能 关系型数据库
阿里云AI产品与云产品最新组合套餐:Token Plan、AI coding及云服务器和建站等组合优惠价
阿里云推出全新“算力+模型+应用”一站式云与AI组合套餐活动,覆盖从个人开发者到中大型企业的全场景需求。核心亮点为分三档定价的Token Plan订阅服务,支持Qwen3.8-Max-Preview大模型调用,错峰时段最低可享0.2折优惠。活动同步推出AI Coding、智能体部署、云电脑托管、0代码建站等十余类场景化组合,搭配99元/年的普惠云服务器、88元/年的入门数据库等经典特惠产品,还为企业提供1V1定制化AI转型方案,大幅降低了不同用户群体拥抱AI的技术门槛与采购成本。
678 111
|
16天前
|
人工智能 JSON 安全
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
阿里云AI安全产品联动防御Fastjson攻击
2600 13
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
|
14天前
|
人工智能 前端开发 Linux
Codex 桌面版安装 + CC Switch 接入第三方 API 完整教程(2026 最新)
2026最新教程:手把手教你安装Codex桌面版,通过CC Switch v3.17.0一键接入Fenno等国产API(兼容OpenAI Responses格式),跳过账号登录,完整启用代码审查、多步任务与上下文感知功能。零基础友好,全程图文实操。(239字)
1866 2
|
2天前
|
人工智能 程序员 API
Codex 接入 DeepSeek-V4-Flash:还能补上识图,提供两套方案
Codex 接入 DeepSeek-V4-Flash 怎么配?本文覆盖 CLI 与桌面端,再用 qwen3-vl-flash 补识图,两套方案可直接照做
|
16天前
|
人工智能 自然语言处理 数据挖掘
Qwen3.8-Max-Preview深度全解析:2.4万亿参数旗舰MoE模型+Token Plan限时优惠完整落地指南
2026年7月,全新旗舰级混合专家大模型Qwen3.8-Max-Preview正式开放抢先体验,作为通义千问Qwen3系列规格最高、综合推理能力顶尖的新一代模型,该模型总参数量达到2.4万亿(2.4T),是当前线上可调用的原生多模态旗舰模型,综合推理水准对标海外顶级Fable 5模型,在复杂工程开发、长文档深度分析、多步骤智能体自治、跨境多语言创作、海量数据挖掘五大高难度业务场景实现跨越式性能提升。
1454 2
|
3天前
Qoder 一周年 × Qwen3.8-Max 正式上线,多重好礼限时领
8月3日,Qwen3.8-Max 正式上线Qoder,迎来Qoder一周年。新老用户可领800次免费调用,下单再赠2000次;夜间(22:00–08:00)调用5折;邀请好友双方得积分与调用额度。
292 0