【Java教程】- 并发编程核心知识解读

Java 并发编程:从入门到"高手"的幽默指南

并发编程就像烹饪:你得知道什么时候加料(线程),什么时候搅拌(同步),不然就会烧锅(死锁)!本文用大白话+生活案例,带你轻松掌握Java并发那些事儿!


📚 文章目录(点击跳转)

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [ volatile关键字](#volatile关键字 synchronized原理 CAS操作 Lock接口 线程池 happens-before原则 CountDownLatch CyclicBarrier ThreadLocal 死锁与避免 Future与Callable 总结与互动) | [ synchronized原理](#volatile关键字 synchronized原理 CAS操作 Lock接口 线程池 happens-before原则 CountDownLatch CyclicBarrier ThreadLocal 死锁与避免 Future与Callable 总结与互动) | [ CAS操作](#volatile关键字 synchronized原理 CAS操作 Lock接口 线程池 happens-before原则 CountDownLatch CyclicBarrier ThreadLocal 死锁与避免 Future与Callable 总结与互动) | [ Lock接口](#volatile关键字 synchronized原理 CAS操作 Lock接口 线程池 happens-before原则 CountDownLatch CyclicBarrier ThreadLocal 死锁与避免 Future与Callable 总结与互动) |
| [ 线程池](#volatile关键字 synchronized原理 CAS操作 Lock接口 线程池 happens-before原则 CountDownLatch CyclicBarrier ThreadLocal 死锁与避免 Future与Callable 总结与互动) | [ happens-before原则](#volatile关键字 synchronized原理 CAS操作 Lock接口 线程池 happens-before原则 CountDownLatch CyclicBarrier ThreadLocal 死锁与避免 Future与Callable 总结与互动) | [ CountDownLatch](#volatile关键字 synchronized原理 CAS操作 Lock接口 线程池 happens-before原则 CountDownLatch CyclicBarrier ThreadLocal 死锁与避免 Future与Callable 总结与互动) | [ CyclicBarrier](#volatile关键字 synchronized原理 CAS操作 Lock接口 线程池 happens-before原则 CountDownLatch CyclicBarrier ThreadLocal 死锁与避免 Future与Callable 总结与互动) |
| [ ThreadLocal](#volatile关键字 synchronized原理 CAS操作 Lock接口 线程池 happens-before原则 CountDownLatch CyclicBarrier ThreadLocal 死锁与避免 Future与Callable 总结与互动) | [ 死锁与避免](#volatile关键字 synchronized原理 CAS操作 Lock接口 线程池 happens-before原则 CountDownLatch CyclicBarrier ThreadLocal 死锁与避免 Future与Callable 总结与互动) | [ Future与Callable](#volatile关键字 synchronized原理 CAS操作 Lock接口 线程池 happens-before原则 CountDownLatch CyclicBarrier ThreadLocal 死锁与避免 Future与Callable 总结与互动) | [ 总结与互动](#volatile关键字 synchronized原理 CAS操作 Lock接口 线程池 happens-before原则 CountDownLatch CyclicBarrier ThreadLocal 死锁与避免 Future与Callable 总结与互动) |


👀 volatile关键字:Java里的"大喇叭"

专业解释
volatile关键字保证变量的内存可见性和禁止指令重排序,但不保证复合操作的原子性。

大白话

就像公司公告栏,经理贴了通知(写volatile变量),所有员工立刻就能看到(内存可见性)。但不能保证员工看完后不修改通知内容(非原子性)。

生活案例

想象一下家里的空调遥控器:你调了温度(写volatile变量),所有家人都能看到新温度(内存可见性)。但如果你和弟弟同时按温度+按钮,可能只加了一次(非原子性)。

java 复制代码
private volatile boolean flag = false; // 就像公告栏上的通知

// 线程A
flag = true; // 贴通知

// 线程B
if (flag) { // 看通知
    // 执行操作
}

面试重点

  • 保证可见性,不保证原子性
  • 适合做状态标志
  • 防止指令重排序

🔒 synchronized原理:Java的"单人间厕所"

专业解释
synchronized通过对象监视器实现线程同步,具有可重入性、自动锁释放和内存可见性保证。

大白话

就像单人间厕所,进去就锁门(获取锁),出来就开门(释放锁)。别人想用?排队等着吧!

锁升级过程
无锁
偏向锁
轻量级锁
重量级锁

代码示例

java 复制代码
public class Bathroom {
    // 实例方法锁 - 锁这个卫生间对象
    public synchronized void use() {
        System.out.println("使用中...");
    }
    
    // 静态方法锁 - 锁所有卫生间
    public static synchronized void clean() {
        System.out.println("打扫中...");
    }
    
    // 代码块锁 - 指定锁哪个对象
    public void repair(Object tool) {
        synchronized(tool) {
            System.out.println("维修中...");
        }
    }
}

🔄 CAS操作:乐观的"换货小哥"

专业解释

CAS(Compare-And-Swap)是一种无锁原子操作,通过比较并交换实现线程安全。

大白话

就像快递员送货:看到门口放的是A商品(预期值),就换成B商品(新值)。如果看到的是C商品,就不换。

ABA问题

你出门时门口是可乐(A),回来时还是可乐(A),但中间被人换成雪碧(B)又换回可乐。CAS会觉得"没变化",但实际被换过!

java 复制代码
AtomicInteger balance = new AtomicInteger(100);

// 模拟CAS操作
boolean success = balance.compareAndSet(100, 50); 
// 如果当前值是100,就改成50

// 解决ABA问题 - 使用带版本号的AtomicStampedReference
AtomicStampedReference<Integer> stampedBalance = 
    new AtomicStampedReference<>(100, 0);

🎯 Lock接口:手动挡的锁车系统

大白话
synchronized是自动挡车(简单但功能有限),Lock是手动挡车(操控灵活但要自己换挡)。

ReentrantLock vs synchronized

特性 synchronized(自动挡) ReentrantLock(手动挡)
锁获取 JVM自动管理 手动lock()/unlock()
可中断 ❌ 不支持 ✅ 支持lockInterruptibly()
公平锁 ❌ 总是非公平 ✅ 可配置公平/非公平
条件变量 ❌ 单一wait/notify ✅ 多个Condition
锁状态查询 ❌ 不支持 ✅ 可查询
java 复制代码
Lock lock = new ReentrantLock(true); // 公平锁
Condition condition = lock.newCondition();

try {
    lock.lock(); // 手动上锁
    while (!conditionMet) {
        condition.await(); // 等待条件
    }
    // 执行业务逻辑
    condition.signal(); // 通知等待线程
} finally {
    lock.unlock(); // 必须手动解锁!
}

🏢 线程池:程序员开的"外包公司"

专业解释

线程池通过复用线程减少创建销毁开销,包含核心线程数、最大线程数、工作队列和拒绝策略。

大白话

就像开外包公司:

  • 核心员工(核心线程):长期雇佣
  • 临时工(非核心线程):忙时招聘
  • 任务清单(工作队列):待处理任务
  • 拒接策略:活太多接不了时的处理方式

线程池工作流程






提交任务
核心线程空闲?
核心线程执行
队列未满?
任务入队
未达最大线程数?
创建临时线程
执行拒绝策略

四种拒绝策略

  1. AbortPolicy:直接抛异常(老板:这活我不接!)
  2. CallerRunsPolicy:让提交者自己干(老板:你自己来吧)
  3. DiscardPolicy:默默丢弃任务(老板:假装没看见)
  4. DiscardOldestPolicy:丢弃最老任务(老板:把最旧的活扔了)

⏰ happens-before原则:Java的"时间管理大师"

大白话

规定哪些操作必须发生在哪些操作之前,就像"先穿袜子再穿鞋"一样有顺序!

六大原则

原则 解释 生活比喻
程序顺序 同一线程内,代码顺序执行 先刷牙再洗脸
监视器锁 解锁先于后续加锁 先出厕所门,别人才能进
volatile 写volatile先于后续读 先贴通知,别人才能看
传递性 A先于B,B先于C,则A先于C 爷爷→爸爸→你
线程启动 start()先于线程内所有操作 先出生,后长大
线程终止 线程内所有操作先于终止检测 先做完工作,再说拜拜

⏱️ CountDownLatch:倒计时的"集合哨"

大白话

就像军训集合,教官数"5、4、3、2、1",所有人都到齐了才下令出发。

使用场景

  • 主线程等待所有子线程完成任务
  • 并行计算,等待所有计算单元完成
  • 服务启动,等待所有组件初始化
java 复制代码
// 模拟5个玩家加载游戏
CountDownLatch latch = new CountDownLatch(5);

for (int i = 1; i <= 5; i++) {
    new Thread(() -> {
        System.out.println("玩家" + Thread.currentThread().getId() + "加载完成");
        latch.countDown(); // 加载完成,倒计时-1
    }).start();
}

latch.await(); // 等待所有玩家加载完成
System.out.println("所有玩家准备就绪,游戏开始!");

🔄 CyclicBarrier:循环使用的"集合点"

大白话

就像朋友聚餐,必须所有人都到齐了才能点菜,吃完一轮还能再来一轮。

与CountDownLatch对比

特性 CountDownLatch(一次性) CyclicBarrier(可循环)
用途 一人等多 多人互等
重用性 ❌ 一次性 ✅ 可reset()重用
计数器 递减,不能重置 可循环使用
额外任务 ❌ 不支持 ✅ 到达屏障后可执行
java 复制代码
// 三个朋友约饭
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
    System.out.println("人到齐了,开始点菜!");
});

for (int i = 1; i <= 3; i++) {
    new Thread(() -> {
        System.out.println(Thread.currentThread().getName() + "出发了");
        try {
            Thread.sleep((long)(Math.random() * 2000));
            System.out.println(Thread.currentThread().getName() + "到达餐厅");
            barrier.await(); // 等待其他人
            System.out.println(Thread.currentThread().getName() + "开始吃饭");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }, "朋友" + i).start();
}

🎒 ThreadLocal:每人一个"储物柜"

专业解释
ThreadLocal为每个线程提供独立的变量副本,实现线程隔离。

大白话

就像健身房每人一个储物柜,你的东西放你的,我的放我的,互不干扰。

内存泄漏警告

java 复制代码
ThreadLocal<User> userHolder = new ThreadLocal<>();

try {
    userHolder.set(currentUser); // 放东西
    // 执行业务逻辑...
} finally {
    userHolder.remove(); // 用完记得清柜子!
    // 不然线程池中线程复用会导致内存泄漏
}

使用场景

  • 数据库连接管理
  • 用户会话信息
  • 日期格式化(SimpleDateFormat非线程安全)

⚠️ 死锁与避免:两人互相鞠躬让路

大白话

就像两个人迎面走来,都往同一侧让路,结果又撞上,再让又撞...永远过不去。

死锁四个必要条件

  1. 互斥:资源不能共享
  2. 持有并等待:拿着A资源等B资源
  3. 不可剥夺:资源不能强制拿走
  4. 循环等待:A等B,B等A

避免死锁的方法

java 复制代码
// 方法1:锁排序(都先锁A再锁B)
private final Object lockA = new Object();
private final Object lockB = new Object();

public void method1() {
    synchronized(lockA) {
        synchronized(lockB) {
            // 业务逻辑
        }
    }
}

public void method2() {
    synchronized(lockA) { // 同样先锁A!
        synchronized(lockB) {
            // 业务逻辑
        }
    }
}

// 方法2:tryLock超时
Lock lock1 = new ReentrantLock();
Lock lock2 = new ReentrantLock();

public void safeMethod() throws InterruptedException {
    while (true) {
        if (lock1.tryLock(50, TimeUnit.MILLISECONDS)) {
            try {
                if (lock2.tryLock(50, TimeUnit.MILLISECONDS)) {
                    try {
                        // 成功获取两个锁
                        return;
                    } finally {
                        lock2.unlock();
                    }
                }
            } finally {
                lock1.unlock();
            }
        }
        // 没获取到,稍等再试
        Thread.sleep((long)(Math.random() * 10));
    }
}

🚀 Future与Callable:带返回值的"外卖订单"

大白话

  • Runnable:像普通任务,干了活没结果
  • Callable:像外卖订单,干了活有结果
  • Future:像外卖订单号,凭它取结果
java 复制代码
// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(3);

// 提交Callable任务
Future<Integer> future = executor.submit(() -> {
    Thread.sleep(2000); // 模拟耗时操作
    return 42; // 返回计算结果
});

// 可以继续做其他事情...

try {
    // 获取结果(最多等3秒)
    Integer result = future.get(3, TimeUnit.SECONDS);
    System.out.println("结果是:" + result);
} catch (TimeoutException e) {
    System.out.println("超时了,取消任务");
    future.cancel(true); // 取消任务
}

executor.shutdown();

CompletableFuture更强大

java 复制代码
// 链式调用,像点外卖还能加备注
CompletableFuture.supplyAsync(() -> "数据")
    .thenApply(data -> data + "处理")
    .thenAccept(result -> System.out.println(result))
    .exceptionally(e -> {
        System.out.println("出错了:" + e);
        return null;
    });

💬 总结与互动

恭喜看到这里!你已经掌握了Java并发编程的核心要点!🎉

记住:并发编程就像开车,规则很重要,但经验更重要。多练习,多思考,少出"车祸"(Bug)。

📊 Java并发知识体系图

Java并发
基础概念
线程 vs 进程
并发 vs 并行
线程生命周期
同步机制
synchronized
对象锁
类锁
锁升级
volatile
可见性
禁止重排序
CAS
原子操作
ABA问题
锁框架
Lock接口
ReentrantLock
ReadWriteLock
StampedLock
线程池
Executor框架
核心参数
拒绝策略
并发工具
CountDownLatch
CyclicBarrier
Semaphore
Phaser
并发集合
ConcurrentHashMap
CopyOnWriteArrayList
BlockingQueue
高级特性
Fork/Join
CompletableFuture
ThreadLocal

🤔 互动时间

评论区聊聊你的并发编程经历吧:

  1. 你在多线程编程中踩过最大的坑是什么?
  2. 你更爱用synchronized还是Lock?为什么?
  3. 有没有遇到过奇葩的死锁场景?怎么解决的?
  4. 如果让你用生活比喻解释"线程池",你会怎么比喻?

分享你的"并发血泪史",点赞最高的送虚拟"防秃洗发水"一瓶!


📝 转载声明

转载请注明原文链接和作者信息。

欢迎转发分享,让更多小伙伴摆脱并发编程的恐惧!


最后送大家一句话

并发不可怕,可怕的是你不敢面对它。

代码可能会死锁,但你的学习之路不会!

祝大家 工作顺利,代码无并发Bug! 🚀

Java并发,痛并快乐着!

相关推荐
椰羊~王小美2 小时前
为什么@Builder 注解默认父类字段不可见
java
一 乐2 小时前
学生宿舍管理|基于springboot + vue学生宿舍管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·助农电商系统
一人の梅雨2 小时前
义乌购商品详情接口进阶实战:批发场景下的精准解析与高可用架构
java·服务器·前端
Sheep Shaun2 小时前
C++11核心特性详解:从右值引用到现代C++编程
开发语言·数据结构·c++·算法
Dontla2 小时前
Mybatis Introduction (Java ORM Framework)
java·开发语言·mybatis
信码由缰2 小时前
JExten:基于Java模块系统(JPMS)构建健壮的插件架构
java·开发语言·架构
Dxy12393102162 小时前
Python使用Playwright入门教程:从环境搭建到实战应用
开发语言·python·playwright
NuageL2 小时前
SpringBoot使用@Scheduled注解实现定时任务
java·spring boot·后端
云深麋鹿2 小时前
三.栈和队列
开发语言·数据结构·c++·算法