java并发问题的实现方案

This commit is contained in:
estom
2025-02-21 16:27:34 +08:00
parent 323bb0fccd
commit 4f8845b63d
3 changed files with 268 additions and 0 deletions

View File

@@ -0,0 +1,170 @@
Java生产者-消费者问题的多种实现方案
以下是5种典型实现方式涵盖从基础同步到高阶工具的使用
## 1. wait()/notify() 基础同步JDK1.0+
核心逻辑通过synchronized和对象锁协调线程。
```
// 共享缓冲区类
class Buffer {
private final LinkedList<Object> list = new LinkedList<>();
private final int MAX_SIZE = 10;
public synchronized void produce() throws InterruptedException {
while (list.size() >= MAX_SIZE) {
wait(); // 缓冲区满时等待<sup>2</sup><sup>7</sup>
}
list.add(new Object());
System.out.println("生产, 当前库存: " + list.size());
notifyAll(); // 唤醒消费者<sup>9</sup>
}
public synchronized void consume() throws InterruptedException {
while (list.isEmpty()) {
wait(); // 缓冲区空时等待<sup>7</sup><sup>9</sup>
}
list.remove();
System.out.println("消费, 当前库存: " + list.size());
notifyAll(); // 唤醒生产者<sup>2</sup>
}
}
```
特点需手动管理锁易出现死锁适合理解底层机制17。
## 2. Lock与ConditionJDK5+
核心逻辑:通过显式锁和条件变量精细化控制。
```
import java.util.concurrent.locks.*;
class Buffer {
private final Lock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
private final int MAX_SIZE = 10;
private LinkedList<Object> list = new LinkedList<>();
public void produce() throws InterruptedException {
lock.lock();
try {
while (list.size() >= MAX_SIZE) {
notFull.await(); // 等待非满条件<sup>7</sup>
}
list.add(new Object());
System.out.println("生产, 当前库存: " + list.size());
notEmpty.signalAll(); // 通知非空条件<sup>7</sup>
} finally {
lock.unlock();
}
}
public void consume() throws InterruptedException {
lock.lock();
try {
while (list.isEmpty()) {
notEmpty.await(); // 等待非空条件<sup>7</sup>
}
list.remove();
System.out.println("消费, 当前库存: " + list.size());
notFull.signalAll(); // 通知非满条件<sup>7</sup>
} finally {
lock.unlock();
}
}
}
```
特点支持多条件变量避免虚假唤醒灵活性高78。
## 3. BlockingQueue 阻塞队列JDK5+
核心逻辑:利用线程安全队列自动处理阻塞。
```
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class Main {
public static void main(String[] args) {
BlockingQueue<Object> queue = new LinkedBlockingQueue<>(10); // 容量限制<sup>3</sup><sup>10</sup>
// 生产者
new Thread(() -> {
while (true) {
try {
queue.put(new Object()); // 队列满时自动阻塞<sup>4</sup><sup>6</sup>
System.out.println("生产, 当前库存: " + queue.size());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}).start();
// 消费者 new Thread(() -> {
while (true) {
try {
queue.take(); // 队列空时自动阻塞<sup>3</sup><sup>10</sup>
System.out.println("消费, 当前库存: " + queue.size());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}).start();
}
}
```
特点代码简洁无需手动同步推荐生产环境使用3610。
## 4. 信号量 SemaphoreJDK5+
核心逻辑:通过许可控制资源访问。
```
import java.util.concurrent.Semaphore;
class Buffer {
private final Semaphore emptySlots = new Semaphore(10); // 初始空位数量<sup>7</sup>
private final Semaphore filledSlots = new Semaphore(0); // 初始已用数量<sup>7</sup>
private final LinkedList<Object> list = new LinkedList<>();
public void produce() throws InterruptedException {
emptySlots.acquire(); // 获取空位许可<sup>7</sup>
synchronized (this) {
list.add(new Object());
System.out.println("生产, 当前库存: " + list.size());
}
filledSlots.release(); // 释放已用许可<sup>7</sup>
}
public void consume() throws InterruptedException {
filledSlots.acquire(); // 获取已用许可<sup>7</sup>
synchronized (this) {
list.remove();
System.out.println("消费, 当前库存: " + list.size());
}
emptySlots.release(); // 释放空位许可<sup>7</sup>
}
}
```
特点适合控制并发资源数但需结合同步块保证原子性78。
## 5. 管道通信(不推荐)
核心逻辑通过PipedInputStream/PipedOutputStream传输数据。
```
import java.io.*;
public class PipeExample {
public static void main(String[] args) throws IOException {
PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream();
pos.connect(pis); // 连接管道<sup>7</sup>
// 生产者写数据
new Thread(() -> {
try {
pos.write("data".getBytes());
pos.close();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
// 消费者读数据
new Thread(() -> {
try {
int data;
while ((data = pis.read()) != -1) {
System.out.print((char) data);
}
pis.close();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
```
特点数据流式传输但难以控制缓冲区实际应用较少7。
## 推荐优先级:
BlockingQueue > Lock/Condition > 信号量 > wait()/notify() > 管道

View File

@@ -0,0 +1,92 @@
# 读写锁问题
读的时候共享、写的时候独占。
## 方案一ReentrantReadWriteLock推荐方案
核心特性:
读锁共享:允许多线程并发读取
写锁独占写操作时完全互斥135
锁降级:写线程可降级为读锁,保证数据一致性
```
import java.util.concurrent.locks.*;
public class ReadWriteResource {
private int value;
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
// 读操作(共享)
public int readValue() {
readLock.lock();
try {
return value;
} finally {
readLock.unlock();
}
}
// 写操作(独占)
public void writeValue(int newValue) {
writeLock.lock();
try {
value = newValue;
} finally {
writeLock.unlock();
}
}
}
```
优势:
明确的读写分离符合业务语义35
支持公平/非公平锁策略19
读操作完全无阻塞适合读多写少场景15
## 方案二StampedLock高性能方案
核心特性:
乐观读无锁读取通过版本号校验数据一致性28
悲观读类似ReentrantReadWriteLock的读锁8
写锁独占:与所有读操作互斥
```
import java.util.concurrent.locks.*;
public class StampedResource {
private int value;
private final StampedLock stampedLock = new StampedLock();
// 乐观读(无锁)
public int optimisticRead() {
long stamp = stampedLock.tryOptimisticRead();
int currentValue = value;
if (!stampedLock.validate(stamp)) { // 检查写冲突<sup>8</sup>
stamp = stampedLock.readLock(); // 降级为悲观读
try {
currentValue = value;
} finally {
stampedLock.unlockRead(stamp);
}
}
return currentValue;
}
// 写操作(独占)
public void writeValue(int newValue) {
long stamp = stampedLock.writeLock();
try {
value = newValue;
} finally {
stampedLock.unlockWrite(stamp);
}
}
}
```
优势:
乐观读性能比传统读锁高30%+读多写少场景8
支持锁升级读锁→写锁8
避免写线程饥饿问题8
## 推荐选择:
优先使用ReentrantReadWriteLock常规读写分离需求35
选择StampedLock读操作占比超过90%的高并发场景8
避免使用synchronized除非并发量极低

View File

@@ -142,3 +142,9 @@
>
> 入门小站。https://rumenz.com/
> BestJavaer。https://github.com/crisxuan/bestJavaer
> 2024年12月23日
> 计划中的项目
> * BestJavaer java-basic java-concurrency jvm https://github.com/crisxuan/bestJavaer/tree/master
> * 书籍 《Java编程思想》 《Java核心技术卷》《Java并发编程实践》
> * 源码 https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/JDK https://github.com/seaswalker/jdk-sourcecode-analysis/blob/master/README.md