生产者和消费者多线程笔试题

<p>背景:消息队列用于异步处理消息,其底层为生产者-消费者模式。现在有一个生产果汁(Juice)的商店,把产生的果汁放在
吧台上,当吧台摆满时不再生产;消费者从吧台购买果汁,当吧台上果汁卖光时需要等待新生产的果汁上架。
<p>使用多线程编程模拟该场景,
<li>使用BlockingQueue模拟吧台,最多暂存10瓶果汁;
<li>当吧台满时等商店最多等待5秒,超过后因生意不好提前打烊,另外该商店一天最多生产100瓶果汁,卖完后打烊;
<li>当吧台为空时消费者需要等待,但每一个消费者最多等待1秒,超时后离开,下一个消费者重新等待,另外打烊后消费者都不再等待了;
<li>商店生产一瓶果汁需要0.1秒,消费者购买过程因付费方式不同随机耗时0.05~0.2秒;

<p>要求:题目已提供生产者的demo,在此基础上改进和扩展(修改生产时间、超时时间等),并完成消费者模型的模拟,
分别实现下面3种场景:
<li>生意不好提前打烊
<li>卖完100瓶后打烊
<li>至少有1名消费者等待超时

答案:
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class Question2 {

private   class Juice {
//...
}

private   BlockingQueue<Juice> queue = new LinkedBlockingQueue<>(10);
/**
* 打烊标记
*/
private volatile boolean close = false;

private void runProducer() {
close = false;
Thread producer = new Thread() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {//该商店一天最多生产100瓶果汁,卖完后打烊;
try {
Thread.sleep(100);//商店生产一瓶果汁需要0.1秒
boolean b = queue.offer(new Juice(), 5, TimeUnit.SECONDS);//当吧台满时等商店最多等待5秒
if (!b) {
System.err.println("生意不好提前打烊");
close = true;
return;
} else {
System.err.println("生产了1瓶,现有" + queue.size() + "瓶在吧台");
}
} catch (InterruptedException e) {
}
}
while (!close && !queue.isEmpty()) {//不是提前打烊并且吧台不为空,则一直休眠0.1秒,直到售完
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
System.err.println("已全部卖完,打烊!");
close = true;
};
};
producer.start();
}
//生意不好提前打烊
private void simulateEarlyClose() {
Thread consumers = new Thread() {
public void run() {
//TODO
while(!close && !queue.isEmpty()) {//没有打烊,并且桌面上有饮料
try {
Random random = new Random();
int num = random.nextInt(151) + 50;///50--200
queue.poll(num, TimeUnit.MILLISECONDS);//消费者购买过程因付费方式不同随机耗时0.05~0.2秒;50-200ms
System.err.println("消费者消费了1瓶,现有" + queue.size() + "瓶在吧台");
Thread.sleep(6000);//先休眠6秒再开始线程
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
};
try {
Thread.sleep(500);//先休眠0.5秒再开始线程
consumers.start();//线程开始
consumers.join();//让主线程等待(WAITING状态),一直等到其他线程不再活动为止
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//卖完100瓶后打烊
private void simulateSoldOut() {
Thread consumers = new Thread() {
public void run() {
//TODO
while(!close && !queue.isEmpty()) {
try {
Random random = new Random();
int num = random.nextInt(151) + 50;///50--200
queue.poll(num, TimeUnit.MILLISECONDS);//消费者购买过程因付费方式不同随机耗时0.05~0.2秒;50-200ms
System.err.println("消费者消费了1瓶,现有" + queue.size() + "瓶在吧台");
Thread.sleep(1000);//先休眠1秒再开始线程
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
};
try {
Thread.sleep(500);
consumers.start();
consumers.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//至少有1名消费者等待超时
//当吧台为空时消费者需要等待,但每一个消费者最多等待1秒,超时后离开,下一个消费者重新等待,另外打烊后消费者都不再等待了
private void simulateWaitingTimeOut() {
for(int i=1;i<=10;i++) {
Thread consumers = new Thread() {
public void run() {
//TODO
while(!close) {//没有打烊
try {
if(queue.isEmpty()) {//如果桌面上没有饮料,则休眠1秒
System.err.println("吧台没有饮料,该消费者等待......");
Thread.sleep(1000);
if(!close && queue.isEmpty()) {
System.err.println("一名消费者因为吧台没有饮料,等待超过1秒钟超时离开");
break;
}
}else {
Random random = new Random();
int num = random.nextInt(151) + 50;///50--200
queue.poll(num, TimeUnit.MILLISECONDS);//消费者购买过程因付费方式不同随机耗时0.05~0.2秒;50-200ms
System.err.println("消费者消费了1瓶,现有" + queue.size() + "瓶在吧台");
Thread.sleep(900);//先休眠0.9秒再开始线程
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
};
try {
Thread.sleep(100);
consumers.start();
// consumers.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public static void main(String[] args) {
System.out.println("==============================");
//        Question2 instance = new Question2();
//        instance.runProducer();
//        instance.simulateEarlyClose();

System.out.println("==============================");
//        Question2 instance2 = new Question2();
//        instance2.runProducer();
//        instance2.simulateSoldOut();

System.out.println("==============================");
Question2 instance3 = new Question2();
instance3.runProducer();
instance3.simulateWaitingTimeOut();
}
}
#java多线程#
全部评论
佩服楼主,现在能这样写代码的不多了
点赞 回复 分享
发布于 2022-06-26 09:52

相关推荐

秋招终于是结束了,给🐮友们分享下秋招的失败经验,希望后人能踩着我的失败前进。传奇耐挂王。米哈游-一共面了两个流程,第一个是程序绿色通道,一面过,二面挂。挂完后被另外一个组捞起来,三面挂(算法没写好)😭网易互娱(纯八股,少项目)-一面很顺利通过,二面被八股拷打挂。网易雷火(纯八股)-线下绿通一面挂(面前基本没准备,忙实习的事)。官网流程笔试过,交叉面挂(第一面做题八股又被干翻了)莉莉丝-笔试全A(比较简单),一面不知道为什么挂,明明聊的特别好,也聊了很久😅,可能是算法又没写好。柠檬微趣-一面二面光速通过,三面挂,这家公司我挺喜欢的,面试流程很快,可惜三面没过灵犀互娱-笔试过,Ai面调试设备出问题了,直接被ai结束流程,直接没了华娱-一面过,二面拒了其他还投了一些中大厂,但是由于投的晚,很多都没捞到面试唯一的offer(鹅神)腾讯-暑假实习从三月干到十一月,功夫不负有心人拿了转正offer,给了sp,以后当一辈子鹅孝子了。总结一下秋招失败原因,主要是因为投的晚+准备少。第一份简历是九月中旬开始投的,当时只投了米和猪,当时觉得可以实习转正,所以没怎么投,相应的准备也很少,基本在allin转正,所以最后大厂都挂了。后面十月份突然告诉我转不了正,当时有点难受了,快速又投了一批,很多公司都是十月中旬投的,这个时间段投的回复的很少,基本都招满了,后面大厂挂完了,当时觉得转正也失败了,秋招也🐔完了,心态有点崩,还好最后还是运气好转正了,不然最后直接备战春招了😂😂。回顾了一下,游戏大厂秋招面试主要都是八股+算法,需要大量时间去准备,没准备可能就和我一样,虽然实习产出非常大,也写了一些比较核心的东西,但总是挂在手撕和八股上面,实习产出主要只能过筛用,八股和算法才是面试中的硬通货,我因为基本allin实习转正这部分准备的比较少,可以说吃亏吃麻了。后面建议小凳,要冲游戏大厂的话,八股和算法必须准备的非常非常充分,很多面试都是纯问八股+写一道算法,这部分准备的不好基本无缘,建议从6月就得开始刷,然后投递也尽量早点,不然也可能吃亏,也别allin转正,有暴雷的风险。我这组里面差点就爆雷了。
想实习转正,又想准备秋招...
点赞 评论 收藏
分享
评论
1
4
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务