diff --git a/Java/04Java并发编程/12 生产者消费者.md b/Java/04Java并发编程/12 生产者消费者.md new file mode 100644 index 00000000..08989dde --- /dev/null +++ b/Java/04Java并发编程/12 生产者消费者.md @@ -0,0 +1,170 @@ +Java生产者-消费者问题的多种实现方案 +以下是5种典型实现方式,涵盖从基础同步到高阶工具的使用: + +## 1. wait()/notify() 基础同步(JDK1.0+) +核心逻辑:通过synchronized和对象锁协调线程。 +``` +// 共享缓冲区类 +class Buffer { + private final LinkedList list = new LinkedList<>(); + private final int MAX_SIZE = 10; + public synchronized void produce() throws InterruptedException { + while (list.size() >= MAX_SIZE) { + wait(); // 缓冲区满时等待27 + } + list.add(new Object()); + System.out.println("生产, 当前库存: " + list.size()); + notifyAll(); // 唤醒消费者9 + } + public synchronized void consume() throws InterruptedException { + while (list.isEmpty()) { + wait(); // 缓冲区空时等待79 + } + list.remove(); + System.out.println("消费, 当前库存: " + list.size()); + notifyAll(); // 唤醒生产者2 + } +} +``` +特点:需手动管理锁,易出现死锁,适合理解底层机制17。 + +## 2. Lock与Condition(JDK5+) +核心逻辑:通过显式锁和条件变量精细化控制。 +``` +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 list = new LinkedList<>(); + public void produce() throws InterruptedException { + lock.lock(); + try { + while (list.size() >= MAX_SIZE) { + notFull.await(); // 等待非满条件7 + } + list.add(new Object()); + System.out.println("生产, 当前库存: " + list.size()); + notEmpty.signalAll(); // 通知非空条件7 + } finally { + lock.unlock(); + } + } + public void consume() throws InterruptedException { + lock.lock(); + try { + while (list.isEmpty()) { + notEmpty.await(); // 等待非空条件7 + } + list.remove(); + System.out.println("消费, 当前库存: " + list.size()); + notFull.signalAll(); // 通知非满条件7 + } 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 queue = new LinkedBlockingQueue<>(10); // 容量限制310 + // 生产者 + new Thread(() -> { + while (true) { + try { + queue.put(new Object()); // 队列满时自动阻塞46 + System.out.println("生产, 当前库存: " + queue.size()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + }).start(); + // 消费者 new Thread(() -> { + while (true) { + try { + queue.take(); // 队列空时自动阻塞310 + System.out.println("消费, 当前库存: " + queue.size()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + }).start(); + } +} +``` +特点:代码简洁,无需手动同步,推荐生产环境使用3610。 + +## 4. 信号量 Semaphore(JDK5+) +核心逻辑:通过许可控制资源访问。 +``` +import java.util.concurrent.Semaphore; +class Buffer { + private final Semaphore emptySlots = new Semaphore(10); // 初始空位数量7 + private final Semaphore filledSlots = new Semaphore(0); // 初始已用数量7 + private final LinkedList list = new LinkedList<>(); + public void produce() throws InterruptedException { + emptySlots.acquire(); // 获取空位许可7 + synchronized (this) { + list.add(new Object()); + System.out.println("生产, 当前库存: " + list.size()); + } + filledSlots.release(); // 释放已用许可7 + } + public void consume() throws InterruptedException { + filledSlots.acquire(); // 获取已用许可7 + synchronized (this) { + list.remove(); + System.out.println("消费, 当前库存: " + list.size()); + } + emptySlots.release(); // 释放空位许可7 + } +} +``` +特点:适合控制并发资源数,但需结合同步块保证原子性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); // 连接管道7 + // 生产者写数据 + 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() > 管道 \ No newline at end of file diff --git a/Java/04Java并发编程/13 读写锁问题.md b/Java/04Java并发编程/13 读写锁问题.md new file mode 100644 index 00000000..08d1e71b --- /dev/null +++ b/Java/04Java并发编程/13 读写锁问题.md @@ -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)) { // 检查写冲突8 + 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:除非并发量极低 \ No newline at end of file diff --git a/Java/Java学习路线.md b/Java/Java学习路线.md index f8bfb7e4..2015c164 100644 --- a/Java/Java学习路线.md +++ b/Java/Java学习路线.md @@ -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