Java 多线程与并发编程详解:原理、实现与实战

Java 多线程与并发编程详解:原理、实现与实战

一、引言:为什么要学习多线程?随着 CPU 核心数的提升,单线程程序已无法充分发挥硬件性能。Java 提供了强大的并发编程支持,允许我们使用多线程来:

提高程序执行效率

响应多个用户请求(如 Web 服务)

实现异步任务、并发数据处理

构建高性能服务器和框架

二、线程基础2.1 什么是线程?线程(Thread)是进程中的最小执行单元,一个进程可以包含多个线程,多个线程共享进程的资源。

📌 线程 VS 进程:

对比项

进程

线程

定义

资源分配单位

CPU 执行单位

资源

独立资源空间

共享资源(如堆)

通信

开销大

更高效

开销

创建销毁开销大

开销较小

2.2 创建线程的方式方式一:继承 Thread 类代码语言:javascript复制java复制编辑public class MyThread extends Thread {

public void run() {

System.out.println("线程运行:" + Thread.currentThread().getName());

}

}

new MyThread().start();方式二:实现 Runnable 接口代码语言:javascript复制java复制编辑public class MyRunnable implements Runnable {

public void run() {

System.out.println("Runnable 线程执行");

}

}

new Thread(new MyRunnable()).start();方式三:使用 Callable + Future代码语言:javascript复制java复制编辑Callable task = () -> {

return "任务完成";

};

FutureTask future = new FutureTask<>(task);

new Thread(future).start();

System.out.println(future.get());三、线程的生命周期与状态图📌 线程状态图如下:

代码语言:javascript复制sql复制编辑新建 NEW

就绪 RUNNABLE ← 唤醒

运行 RUNNING

↓ ↑

阻塞 BLOCKED/WAITING/TIMED_WAITING

终止 TERMINATED四、线程同步与锁机制4.1 为什么需要同步?多个线程同时访问共享资源时,可能产生“竞态条件”:

代码语言:javascript复制java复制编辑class Counter {

int count = 0;

public void add() {

count++;

}

}多个线程同时调用 add(),可能导致最终 count 错误。

4.2 synchronized 同步关键字修饰实例方法代码语言:javascript复制java复制编辑public synchronized void add() {

count++;

}修饰代码块代码语言:javascript复制java复制编辑public void add() {

synchronized (this) {

count++;

}

}修饰静态方法(类锁)代码语言:javascript复制java复制编辑public static synchronized void staticMethod() {}📌 原理:

synchronized 会加锁对象的 monitor(监视器锁),底层依赖 JVM 实现。

4.3 死锁示例与避免代码语言:javascript复制java复制编辑public void deadlock() {

synchronized (resourceA) {

synchronized (resourceB) {

// 死锁风险

}

}

}✅ 避免方式:

保持加锁顺序一致

设置超时(如 tryLock())

五、常见并发工具类(Java.util.concurrent)5.1 ReentrantLock(可重入锁)代码语言:javascript复制java复制编辑Lock lock = new ReentrantLock();

try {

lock.lock();

// 临界区

} finally {

lock.unlock();

}📌 支持:

公平锁 / 非公平锁

可中断锁

可重入

条件变量(Condition)

5.2 CountDownLatch:等待多个线程完成代码语言:javascript复制java复制编辑CountDownLatch latch = new CountDownLatch(3);

for (int i = 0; i < 3; i++) {

new Thread(() -> {

// 执行任务

latch.countDown(); // 完成一次

}).start();

}

latch.await(); // 等待3个线程执行完5.3 CyclicBarrier:线程集合后统一执行代码语言:javascript复制java复制编辑CyclicBarrier barrier = new CyclicBarrier(3, () -> {

System.out.println("三线程到达,开始执行任务");

});适合多个线程协作的场景,例如并行计算。

5.4 Semaphore:控制并发数代码语言:javascript复制java复制编辑Semaphore semaphore = new Semaphore(3);

semaphore.acquire();

try {

// 执行任务

} finally {

semaphore.release();

}控制访问资源的最大线程数,如连接池。

六、线程池详解(Executor 框架)6.1 使用线程池的优势 减少资源创建/销毁开销

提高响应速度

控制最大并发数

6.2 Executors 创建线程池代码语言:javascript复制java复制编辑ExecutorService pool = Executors.newFixedThreadPool(5);

pool.execute(() -> {

System.out.println("线程池任务执行");

});📌 常见线程池类型:

类型

特点

newFixedThreadPool

固定线程数,适合稳定负载

newCachedThreadPool

自动扩容/回收线程,适合短任务

newSingleThreadPool

单线程,适合顺序执行

newScheduledPool

定时任务调度

6.3 自定义线程池参数(推荐)代码语言:javascript复制java复制编辑ThreadPoolExecutor executor = new ThreadPoolExecutor(

5, 10,

60, TimeUnit.SECONDS,

new LinkedBlockingQueue<>(100),

Executors.defaultThreadFactory(),

new ThreadPoolExecutor.AbortPolicy()

);📌 参数说明图解:

代码语言:javascript复制nginx复制编辑corePoolSize → 核心线程数

maximumPoolSize → 最大线程数

keepAliveTime → 空闲线程存活时间

workQueue → 任务队列

handler → 拒绝策略七、线程安全集合类7.1 常见类型类名

描述

ConcurrentHashMap

线程安全的 HashMap

CopyOnWriteArrayList

读多写少的线程安全列表

BlockingQueue

支持阻塞的队列接口

八、volatile 与原子操作类8.1 volatile:可见性关键字代码语言:javascript复制java复制编辑volatile boolean running = true;📌 保证线程间变量的 可见性,但不保证原子性。

8.2 原子类:AtomicInteger代码语言:javascript复制java复制编辑AtomicInteger counter = new AtomicInteger();

counter.incrementAndGet(); // 原子自增基于 CAS(Compare and Swap)机制实现无锁并发。

九、并发问题与调试技巧9.1 经典并发问题问题

说明

竞态条件

多线程抢占资源导致结果异常

死锁

线程互相等待资源,永不释放

饥饿

某线程长期得不到资源

活锁

不停改变状态但无法前进

9.2 常用调试工具与命令 jstack: 查看线程堆栈

VisualVM: 图形化分析工具

Java Flight Recorder: Java 性能监控

十、案例实战:模拟银行取款系统代码语言:javascript复制java复制编辑class Bank {

private int balance = 1000;

public synchronized void withdraw(int amount) {

if (balance >= amount) {

try { Thread.sleep(100); } catch (Exception e) {}

balance -= amount;

System.out.println(Thread.currentThread().getName() + " 取款成功,剩余:" + balance);

} else {

System.out.println(Thread.currentThread().getName() + " 余额不足");

}

}

}代码语言:javascript复制java复制编辑public class Test {

public static void main(String[] args) {

Bank bank = new Bank();

Runnable r = () -> bank.withdraw(800);

new Thread(r, "用户A").start();

new Thread(r, "用户B").start();

}

}📌 观察输出结果并测试同步效果。

十一、总结与进阶方向11.1 本文回顾要点: 多线程基础与创建方式

同步机制(synchronized、Lock)

并发工具类(CountDownLatch、Semaphore 等)

线程池与并发集合

volatile 与原子类

并发调试方法

11.2 推荐进阶方向: 学习 AQS(AbstractQueuedSynchronizer)原理

掌握 Fork/Join 框架

熟练使用 CompletableFuture 异步处理

深入理解 Java 内存模型(JMM)

💫 相关推荐

如何用AE渲染出高清视频
约彩365app下载

如何用AE渲染出高清视频

📅 09-29 👀 4670
球王专属!梅西的阿迪达斯定制款球鞋曝光:球鞋上印了三颗金星!
正版闪盾哪里买得到?(官方授权店铺购买指南)
约彩365app下载

正版闪盾哪里买得到?(官方授权店铺购买指南)

📅 08-26 👀 1350
我挺你是什麼意思
365双试投注是什么

我挺你是什麼意思

📅 09-04 👀 8494
最全的北京周边旅游攻略,收藏起来
约彩365app下载

最全的北京周边旅游攻略,收藏起来

📅 02-19 👀 1300
LOL游戏结束就掉线原因
约彩365app下载

LOL游戏结束就掉线原因

📅 11-25 👀 297
将 iPad 照片传输到 Android 的方法:综合指南
约彩365app下载

将 iPad 照片传输到 Android 的方法:综合指南

📅 09-27 👀 9450
传奇国度新服开服多少天合区
365bet官网是什么

传奇国度新服开服多少天合区

📅 02-02 👀 4828
哇哦!快来瞧瞧上海更新学校到底啥样
365bet官网是什么

哇哦!快来瞧瞧上海更新学校到底啥样

📅 02-03 👀 5294