多线程 - 生产者与消费者
经典面试题
数据容器:封装生产、消费所需的数据。
生产者:从容器中填装东西,东西生产好了,及时通知消费者。
消费者:从容器取数据,东西取完了,及时通知生存者生产。
分析
没有任何实战价值,但是面试的时候会问。
本文主要是想介绍 Thread 相关的函数,一般不会用到这么底层的代码。
推荐方案:使用读写锁,或者直接使用阻塞队列
Wait、Notify、NotifyAll
主要就介绍这三个方法,本案例也就用到他们:
如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
对象叫Container,A线程不再使用Container,那就等待
如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
A线程等待了,但是得通知某一个等待的线程来使用Container
如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。
通知所有在等待的线程
其它方法也顺带提一下:
- join():加入其它线程,并且等待join的线程执行完成,再执行自己的
- join(millis):等待被join的线程的时间最长为millis毫秒。如果在millis毫秒内被join的线程还没有执行结束,则不再等待。
- yield():给优先级高或者相同的线程让步
- setDaemon():将普通线程变为后台线程,直接使用方法即可。
数据容器:
public class Container {
private int count = 0;
private Vector<String> vector = new Vector<>();
private static final Container CONTAINER = new Container();
private Container() {
}
public static Container getContainer() {
return CONTAINER;
}
public synchronized void put() {
//通知其它线程
this.notifyAll();
String name = Thread.currentThread().getName();
while (vector.size() > 10) {
System.out.println("container is filled...");
try {
//如果集合内容超过10等待
this.wait();
System.out.println("###" + name + "等待");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count++;
vector.add("Milk:" + count);
System.out.println("###" + name + "生产一个产品");
}
public synchronized String get() {
//通知其它线程
this.notifyAll();
String name = Thread.currentThread().getName();
String milk = null;
while (vector.size() <= 0) {
System.out.println("container is empty...");
try {
//如果集合内容为0等待
this.wait();
System.out.println("---" + name + "等待");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
milk = vector.get(0);
vector.remove(0);
System.out.println("---" + name + "消费一个产品");
return milk;
}
}
生产者
public class Fatory extends Thread {
private Container container = Container.getContainer();
private boolean threadStop = false;
public Fatory(String name) {
super(name);
this.start();
}
@Override
public void run(){
while (!threadStop) {
try {
container.put();
Thread.sleep(300);
} catch (InterruptedException e) {
Thread.interrupted();
}
}
}
public void threadStop(){
this.threadStop=true;
}
}
消费者:
public class Shop extends Thread {
private Container container = Container.getContainer();
private boolean threadStop = false;
public Shop(String name) {
super(name);
this.start();
}
@Override
public void run() {
while (!threadStop) {
try {
container.get();
Thread.sleep(800);
} catch (InterruptedException e) {
Thread.interrupted();
}
}
}
public void threadStop() {
this.threadStop = true;
}
}
测试方法:
public class Test {
public static void main(String[] args) {
new Fatory("factoryA");
new Fatory("factoryB");
new Shop("shopA");
new Shop("shopB");
new Shop("shopC");
}
}
疯狂的妞妞 :每一天,做什么都好,不要什么都不做!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY