【Java 并发】【应用】经典的生产者、消费者
1 前言
闲来无事,复习复习并发中常用到的一些协调多线程的工具哈。
2 基于Java队列的实现
生产者跟消费者之间要协调,他俩会出现碰撞的地方就是存放东西的容器,所以我们可以直接拿一个线程安全的队列来做容器即可,比如我这里用的 ArrayBlockingQueue:
/** * @author: xjx * @description */ public class SyncDemo { /** * 容器大小 */ private int len = 10; /** * 队列 */ private ArrayBlockingQueue queue = new ArrayBlockingQueue(len); /** * 生产 * add put(阻塞) offer(不阻塞) */ public void product(int num) throws InterruptedException { queue.put(num); System.out.println(String.format("%s-生产了-%s", Thread.currentThread().getName(), num)); } /** * 消费 * poll(不阻塞) take(阻塞) peek(只看不取) */ public int consume() throws InterruptedException { Object num = queue.take(); System.out.println(String.format("%s-消费了-%s", Thread.currentThread().getName(), num)); return ((int) num); } public static void main(String[] args) throws InterruptedException { SyncDemo demo = new SyncDemo(); Thread consumer = new Thread(() -> { try { for (int i = 0; i < 100; i++) { demo.consume(); } } catch (InterruptedException e) { e.printStackTrace(); } }); Thread product = new Thread(() -> { try { for (int i = 0; i < 100; i++) { demo.product(i); } } catch (InterruptedException e) { e.printStackTrace(); } }); product.start(); consumer.start(); product.join(); consumer.join(); } }
3 基于Java内置锁的实现
那么我们不用安全队列的情况下,基于最原始的 Java 内置锁方式的实现如下:
/** * @author: xjx * @description */ public class SyncedDemo { /** * 容器大小 */ private int len = 10; /** * 容器 */ private List<Integer> list = Lists.newArrayListWithCapacity(len); /** * 同步对象 */ private final Object obj = new Object(); /** * 生产 * add put(阻塞) offer(不阻塞) */ public void product(int num) throws InterruptedException { synchronized (obj) { while (list.size() == len) { obj.wait(); } // 不满了 可以放东西了 list.add(num); System.out.println(String.format("%s-生产了-%s", Thread.currentThread().getName(), num)); // 唤醒消费者 obj.notify(); } } /** * 消费 * poll(不阻塞) take(阻塞) peek(只看不取) */ public void consume() throws InterruptedException { synchronized (obj) { while (list.size() <= 0) { obj.wait(); } // 不空,消费一个 Integer num = list.remove(list.size() - 1); System.out.println(String.format("%s-消费了-%s", Thread.currentThread().getName(), num)); // 唤醒生产者 obj.notify(); } } public static void main(String[] args) throws InterruptedException { SyncedDemo demo = new SyncedDemo(); Thread consumer = new Thread(() -> { try { for (int i = 0; i < 100; i++) { demo.consume(); } } catch (InterruptedException e) { e.printStackTrace(); } }); Thread product = new Thread(() -> { try { for (int i = 0; i < 100; i++) { demo.product(i); } } catch (InterruptedException e) { e.printStackTrace(); } }); product.start(); consumer.start(); product.join(); consumer.join(); } }
4 基于AQS延申的同步工具类的实现
基于AQS 延申出很多同步工具类,我这里用 ReentrantLock 来实现下:
public class ReentrantSyncDemo { /** * 容器大小 */ private int len = 10; /** * 容器 */ private List<Integer> list = Lists.newArrayListWithCapacity(len); /** * 同步对象 */ private ReentrantLock lock = new ReentrantLock(); private Condition notFull = lock.newCondition(); private Condition notEmpty = lock.newCondition(); /** * 生产 * add put(阻塞) offer(不阻塞) */ public void product(int num) throws InterruptedException { lock.lock(); try { while (list.size() == len) { notFull.await(); } // 不满了 可以放东西了 list.add(num); System.out.println(String.format("%s-生产了-%s", Thread.currentThread().getName(), num)); // 唤醒消费者 notEmpty.signal(); } finally { lock.unlock(); } } /** * 消费 * poll(不阻塞) take(阻塞) peek(只看不取) */ public void consume() throws InterruptedException { lock.lock(); try { while (list.size() <= 0) { notEmpty.await(); } // 不空,消费一个 Integer num = list.remove(list.size() - 1); System.out.println(String.format("%s-消费了-%s", Thread.currentThread().getName(), num)); // 唤醒生产者 notFull.signal(); } finally { lock.unlock(); } } public static void main(String[] args) throws InterruptedException { ReentrantSyncDemo demo = new ReentrantSyncDemo(); Thread consumer = new Thread(() -> { try { for (int i = 0; i < 100; i++) { demo.consume(); } } catch (InterruptedException e) { e.printStackTrace(); } }); Thread product = new Thread(() -> { try { for (int i = 0; i < 100; i++) { demo.product(i); } } catch (InterruptedException e) { e.printStackTrace(); } }); product.start(); consumer.start(); product.join(); consumer.join(); } }
5 小结
好啦,大概先想到这三种,有理解不对的地方欢迎指正哈。
分类:
源码 / Java 并发
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了