一、需求分析:

模拟卖票窗口,实现5个窗口同时卖100张票(代码为了截图采用30张票)

知识点:多线程,锁,多线程的安全问题,线程的生命周期

二、代码实现

public class TestSellTickets {//此处也可采用普通的int//static int count = 30;static AtomicInteger count = new AtomicInteger(30);static String[] windows = {"窗口1","窗口2","窗口3","窗口4","窗口5"};public static void main(String[] args) {Thread[] threads = new Thread[5];Object o =new Object();for (int i=0;i<5;i++){threads[i] = new Thread(() -> { //采用lambda表达式创建线程,同时初始化给threads中的每个线程threads[i]while (true){if (count.get() >0){    //加锁前后双重判断,避免浪费锁资源synchronized (o){ //加锁,避免多个窗口同时卖一张票,实现线程安全if (count.get() >0) {   //加锁前后双重判断,避免浪费锁资源try {Thread.sleep(100);  //模拟卖票业务,停顿0.1秒} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 卖出第" + count + "张票");count.decrementAndGet();}else{System.out.println("余票不足停止售票~");break;}}}else{System.out.println("余票不足停止售票~");break;}}}, windows[i]);//windows[i]定义线程的名称}for (Thread thread:threads){thread.start(); //启动线程}}
}

代码中的关键部分已经注释

运行结果:

三、分析

通过以上代码,我们成功模拟了卖票问题,并且没有产生线程安全问题,
但是但是但是
为什么只要窗口1卖票,其他窗口并没有卖票,这样显然并不合理

原因:
捋一捋五个线程的生命周期,在上面的运行结果中,很明显是窗口1线start(),此时窗口1进入Runnable(可运行状态),尝试获取锁,发现并没有其他窗口持有锁,窗口1成功拿到锁并执行业务进行卖票;
而在窗口1之后启动的窗口2345在启动之后也尝试去获取锁,发现锁已经被别人拿走了,于是进入锁池,(注意:在同步状态下,没有获取到锁的会进入到等待队列中的锁池,锁池会比等待队列中的其他线程更优先于去获取锁);
在窗口1卖完1张票之后,开始释放锁,此时,窗口2345同时发现锁空了,正准备上去抢,结果窗口1发现自己又需要锁了,于是再次获取锁,窗口1一直围绕在锁的旁边,而窗口2345在锁池中的板凳上坐着,肯定没有窗口1抢的快。

四、解决

分析完问题的产生的原因之后,怎么解决呢,当然从源头下手,让窗口1在卖完一张票释放锁后晕眩(睡眠)10毫秒,让窗口2345启动冲刺去抢锁;

这里,我们采用了ReentrantLock锁(注意,最后一定要记得释放锁)

public class TestSellTickets2 {static int counts =100;static String[] windows={"窗口1","窗口2","窗口3","窗口4","窗口5"};public static void main(String[] args) {Lock lock = new ReentrantLock();Thread[] threads = new Thread[5];for (int i=0;i<5;i++){threads[i] = new Thread(() -> {while (true) {if (counts > 0) {lock.lock();try {if (counts > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "卖出第" + counts + "张票");counts--;} else {System.out.println(Thread.currentThread().getName() + "发现余票不足,停止售票");break;}}finally {lock.unlock(); //释放锁try {Thread.sleep(10);   //晕眩10毫秒} catch (InterruptedException e) {e.printStackTrace();}}} else {System.out.println(Thread.currentThread().getName() + "发现余票不足,停止售票");break;}}},windows[i]);}for (Thread thread:threads){thread.start();}}
}

运行结果:

此时,发现5个窗口同时开始卖票,效率大大提高

欢迎评论区留下你的建议,大家一起讨论~~~

多线程卖票深刻分析:为什么会出现只有一个窗口卖票的现象相关推荐

  1. 想去看演唱却总是抢不到票?教你用Python制作一个自动抢票脚本

    前言 嗨喽!大家好,这里是魔王!! 大麦网,是中国综合类现场娱乐票务营销平台,业务覆盖演唱会. 话剧.音乐剧.体育赛事等领域. 但是因为票数有限,还有黄牛们不能丢了饭碗,所以导致了,很多人都抢不到票 ...

  2. 周杰伦演唱会总是抢不到票?教你用Python做一个自动抢票脚本!

    相信想去周董演唱会的大家都用过大麦网抢票吧? 可是 抢不到啊 该说不说 我抢到了 那么,今天带大家用Python来制作一个自动抢票的脚本小程序! 知识点: 面向对象编程 selenium 操作浏览器 ...

  3. 周杰伦演唱会总是抢不到票?教你用Python做一个自动抢票脚本

    相信想去周董演唱会的大家都用过大麦网抢票吧? 可是 抢不到啊 该说不说 我抢到了 那么,今天带大家用Python来制作一个自动抢票的脚本小程序! 知识点: 面向对象编程 selenium 操作浏览器 ...

  4. 四窗口卖票 自己的票

    四窗口卖票 自己的票 卖票线程 package demon四个窗口卖票;public class TicketSale extends Thread {public TicketSale(){}pub ...

  5. “票卡分析专用工具”功能介绍

    "票卡分析专用工具"的由来 ​​​        从一个萌动少年开始,来到北京,从此开始了北漂的生活...... 毕业工作虽然还没到八年,但有时候会回首想想一些工作方面的经历,总想 ...

  6. 多线程实现4个窗口卖100张票

    技能点: 1.如何保证线程是多线程运行,而且不出现负票? 第一个while判断是外部判断,用于保持售票:而且在while循环中嵌入synchronized (){}是惯用方法,如果此处把while换为 ...

  7. java多线程同步 多窗口卖票实例_java多线程之火车售票系统模拟实例

    1.前言 为了学习多线程共享与通信,我们模拟一个火车售票系统,假设有10张火车票,三个窗口(也就是三个线程)同时进行售票. 2.非同步代码 package com.tl.skyLine.thread; ...

  8. java 卖票问题_Java之多线程窗口卖票问题(Thread)

    /** * * 例子:创建三个窗口卖票,总票数为100张.使用继承Thread类的方式 * * 存在线程的安全问题,待解决. * */ class Window extends Thread{ pri ...

  9. 程序模拟电影院窗口卖票,多线程Demo

    某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票 卖电影票Demo 实现步骤 1.SellTicket类 2.SellTicketDemo测试类 3.测 ...

最新文章

  1. Spring从菜鸟到高手(四)(上)使用JdbcTemplate类实现用户登陆验证、批量更新
  2. android程序贴吧,【Android 教程总结贴】归纳所有android贴
  3. 终于有人手把手用Java实现超市管理系统
  4. IC/FPGA 技术交流
  5. 3.7 测试时的 BatchNorm-深度学习第二课《改善深层神经网络》-Stanford吴恩达教授
  6. (视频+图文)机器学习入门系列-第3章 逻辑回归
  7. ActiveMQ的Transport Connectors配置(六)
  8. [Redux/Mobx] 在Redux中怎么发起网络请求?
  9. 数组名与指向数组的指针之间的联系与区别【数据结构】
  10. Hbase 实现微博好友关注功能
  11. 你不一定知道的vb6(2)
  12. 思科研究称80%的指纹认证机制均可遭绕过
  13. [POI2006]Tet-Tetris 3D
  14. node 版本管理器 之 nvm 安装与使用
  15. Vue+Webpack打造todo应用
  16. Linux学习--CentOS可视化配置网络
  17. 初识 Hbase 数据库
  18. java 如何保证配色通用_简单实用的通用配色法则,可以直接套用到日常的穿搭中...
  19. Dev-C++如何更改字体大小
  20. 一位研究生导师的肺腑之言

热门文章

  1. 51单片机的串口通迅
  2. python二维字典简单赋值取值
  3. PXI知多少?—PXI背景及PXI机箱
  4. 深入理解vue中的slot与slot-scope (简单易懂)
  5. 推荐系统学习(一)——推荐引擎初探
  6. vue3(vite)设置代理,封装axios,api解耦
  7. 2. 认识O(logN)的排序
  8. 亚马逊云科技携手埃森哲共助行业云转型
  9. 2023年留学基金委(CSC)公派访问学者博士后项目选派办法及解读
  10. a padding to disable MSIE and Chrome friendly error page解决方案