3个窗口卖票java_三个窗口同时卖火车票,如何用代码将该场景实现?
今天是我自学Java的第33天。
感谢你的陪伴,你的陪伴便是对我最大的鼓励。
话不多说,开始今天的学习:线程同步。
想必很多小伙伴应该都经历过去火车站买票的情况。
现有一个案例:火车站有3个售票窗口,一共有100张票要卖,3个窗口同时卖。
对于这种情形,如何使用Java代码来实现?
一、多窗口卖票案例
根据我们这几天的学习,很显然要创建三个线程来解决这种情况,我们选择使用实现Runnable接口的这种方式来创建线程:
①创建一个类MyRunnable,实现Runnable接口。
②有100张票要售卖。
也就是说类中有一个成员变量是100。
③重写run方法。
④创建一个循环语句:
因为需要一直卖票,直到票被卖完为止,所以使用循环语句,每循环一次卖一张票,打印卖票信息并且将ticket减一。
⑤创建MyRunnable对象。
⑥创建三个线程。
将MyRunnable对象初始化赋值给它,并且给各个窗口命名。
⑦启动线程。
根据我们前几天学习的线程,我们可以写出这样的代码来实现卖票的需求。
现在看看打印结果:
咦,发现结果怎么和我想象的不一样?
票确实是在卖票,但怎么会是无序的呢?并且有时还会出现重复票。
这是为什么?
因为Java虚拟机的抢占式调度,我窗口壹先进来了,但是我还没有执行完,就切换到窗口贰了。
run方法中的while循环语句执行也是需要时间的,虽然它执行起来很快,需要的时间也很少,但是线程切换更加地快。
于是就会出现:窗口贰还在打印第6张票,窗口叁连续卖了好几张都卖完了这种情况。
当我们使用多个线程访问同一资源的时候,且多个线程对该资源都有操作,就容易出现线程安全问题。
什么叫线程安全问题?
通俗点理解就是:线程一在执行任务的时候,还没有执行完,线程二也进来执行线程一还没执行完的任务,这就乱套了呀,这种情况就是线程不安全。
要解决上述多线程并发访问一个资源的安全性问题:也就是解决重复票与票无序的问题,Java中提供了同步机制(synchronized)来解决
二、同步代码块
用synchronized这个关键字来修饰代码块:
①Object是Java里的顶层父类,它代表了任意对象。
②同步代码块:锁住了lock这个对象,里面的代码就只允许执行一个线程的代码。
什么意思呢?
就是现在进来了一个线程,只要你进入了我锁住的这块代码,你就必须得将我锁住的这块代码执行完。在执行完之前,别的线程根本就进不来。
其中lock可以是任意对象,但要保证它的唯一性。
这又是什么意思呢?
lock就好比是一把锁,线程一、线程二,无论哪个线程进来,面对的lock都是同一把锁,一次就只能进入一个。
如果我们将①里面创建Object对象的代码放入到run方法里面,这样就会出现一个问题:
线程启动就会执行run方法,这样的话启动三个线程就会执行三次run方法,如果①在run方法里面,就会new三个Object对象,也就是三个不同的lock,这样的话就相当于有三把不同的锁,还是会乱序。
这就是lock要保证它的唯一性的原因。
我们再看看控制台输出情况:
票的打印确实是有序的了,也没有重复卖票。
但是现在问题又来了:第0张票和第-1张票怎么来的?
为什么会出现这种情况?
我们仔细看看while循环的代码:
现在窗口壹在售卖第1张票,卖完之后票数ticket等于0了。
但是窗口贰和窗口叁它们两个线程在干嘛?
它们早就已经进入while循环了,只不过因为先前synchronized锁住的代码块,窗口壹在里面,它们没法进去,只能等在synchronized外面,但是它们已经在while循环里面。
我们仔细分析下这个流程:
(1)窗口壹打印完第1张票,ticket变成了0,通过while循环的判断语句(ticket>0),窗口壹无法进入while循环了。
(2)窗口贰在while循环里面等着,看到窗口壹出来了立马就抢先进去了,这个时候ticket已经为0了,所以它打印第0张票,于是ticket变成了-1,窗口贰循环结束出来了,通过while循环的判断语句(ticket>0),窗口贰也无法进入while循环了。
(3)窗口叁在while循环里面等着,看到刚才抢先自己一步进入的窗口贰出来了,自己终于可以进去了,这个时候ticket已经为-1了,所以它打印第-1张票,于是ticket变成了-2,窗口叁循环结束出来了,通过while循环的判断语句(ticket>0),窗口叁也无法进入while循环了。
以上就是第0张票和第-1张票的由来。
除了这个问题还有一个问题:窗口壹会一直售卖好多张票。我们如何让窗口壹卖第一张,窗口贰卖第二张,窗口叁卖第三张,窗口壹卖第四张……这样一直循环依次卖票?
面对这两个问题,我们将代码进一步优化:
③加一个判断语句:如果票数小于等于0,就直接结束循环,不执行后面的语句了。
所以当窗口壹打印完第1张票,ticket变成了0。这时就算窗口贰、窗口叁这两个线程进入了synchronized里面,也会有一个if判断语句中的break直接将循环结束掉。
④让该线程睡眠10毫秒:
Thread有一个静态方法sleep(),sleep是睡眠的意思,也就是说窗口壹执行完语句后,会让它睡眠10毫秒,这样的话窗口贰就能进去执行,不然的话根据Java虚拟机的抢占式调度,下一次执行语句的可能还是窗口壹。
以上就是对同步代码块的说明,除了同步代码块,还有同步方法和Lock锁也可以实现同样的功能。
三、同步方法和Lock锁
1.同步方法
同步代码块里面的代码,我们可以将其提取成一个方法,而用synchronized这个关键字来修饰的方法就叫做同步方法:
①线程进来遇到同步方法后,就只能进去一个线程,其它线程得等这个线程执行完后才能进去。
②同步方法:格式就是在方法声明上加上synchronized这个关键字。
③如果ticket大于0就打印输出。
这个同步方法的作用和同步代码块是一样的。
2.Lock锁
lock是一个接口,它提供了比同步代码块和同步方法更广泛的锁定操作,更加地强大和体现了面向对象。
Lock锁也称同步锁,加锁与释放锁方法化了。
①Lock是一个接口,无法实例化创建对象,需要其实现类创建对象。
②lock方法:顾名思义就是上锁,也就是说上锁后的空间线程只能进去一个,其他线程就不去。
③unlock方法:顾名思义就是解锁,将锁解开了,其他线程也就能进去了。
这用我们现实里的一个例子来理解就是:
②就相当于我们去上厕所,将门给锁上,这样其他人就进不来了。
③就相当于我们上完厕所,将门给解开,这样其他人就能进去了。
一个人就相当于是一个线程。
以上就是同步方法和Lock锁,它们和同步代码块的作用其实是大同小异的。
总结:
谢谢你的观看
如果可以的话,麻烦帮忙点个赞,谢谢你
3个窗口卖票java_三个窗口同时卖火车票,如何用代码将该场景实现?相关推荐
- 卖票问题 - 三种解决方法
目录 案例:卖票 出现的问题 解决方法: 方式一:同步代码块 方式二:同步方法 方式三:Lock锁 案例:卖票 /**例子:创建三个窗口卖票,总票数为100张.使用实现Runnable接口的方式* @ ...
- 【Java9】异常,finally,线程创建(卖票),线程同步(卖包子),线程练习
文章目录 1.错误和异常区别:Arrays.toString(array) 2.编译和运行异常:SimpleDateFormat 3.处理异常:方法声明抛出 4.finally关键字:catch相当于 ...
- 多线程卖票深刻分析:为什么会出现只有一个窗口卖票的现象
一.需求分析: 模拟卖票窗口,实现5个窗口同时卖100张票(代码为了截图采用30张票) 知识点:多线程,锁,多线程的安全问题,线程的生命周期 二.代码实现 public class TestSellT ...
- 如何高效实现多窗口卖票
多窗口卖票是常见的多线程问题,来看看要怎么搞 方法1,不建议的使用方式 package concurrent.me.ticket;import java.util.ArrayList; import ...
- 哈尔滨火车站下面有三个火车票代售点,假如哈尔滨到北京的火车票总共是200张,如何用程序来实现三个售票点同时卖票的功能。
題目內容: 哈尔滨火车站下面有三个火车票代售点,假如哈尔滨到北京的火车票总共是200张,如何用程序来实现三个售票点同时卖票的功能. 哈尔滨站卖了一张票,还剩9张票. 香坊站卖了一张票,还剩8张票. 哈 ...
- 多线程经典问题 卖票问题
/** 需求:某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票 思路: ① 定义一个类Ticket实现Runnable接口,里面定义一个成员变量:pri ...
- 线程安全问题经典案例---卖票
在入门多线程的时候,看到过不少的案例,其中卖票案例尤为经典,在这里自己也记录一下,同时加深对于线程安全的理解: 案例场景 情景一: 现在有一个电影院,马上要上映电影<战狼5>,电 ...
- 多线程:线程同步与死锁(卖票案例)、线程通信、生产者与消费者
卖票案例 5个窗口同时卖票: 使用Runnable接口,只创建了一个ticket1对象,5个线程共享此对象,实现了资源共享. public class ticket1 implements Runna ...
- Java线程安全(卖票案例) 如何解决线程安全(synchronized ,显示锁Lock)
文章目录 线程安全 解决方法: 1.同步代码块 2.同步方法 3.显示锁 显示锁与隐式锁的区别 4.公平锁与非公平锁 线程安全 经典问题:卖票问题,多个线程一起执行该任务,当余票只有1一张时,三个线程 ...
最新文章
- Android -- Messenger与Service
- java中String对象和String变量
- 英特尔图形学专家被AMD挖走,研发实时光追技术,从部门主管变成副总裁
- C++中流的基本概念
- 执行SQL-MapperProxy.invoke()
- 夜深人静,想规划一下短期
- 一个实时收集MySql变更记录的组件CanalSharp.AspNetCore
- input子系统基础之按键4——输入核心层源码分析
- java system类_Java System类mapLibraryName()方法及示例
- [java] DOS编译 .java 文件得到 .class 文件 并执行 以及使用外部 .jar包 时的命令...
- BZOJ3531-[Sdoi2014]旅行(树剖+线段树动态开点)
- ASCLL码表完整版
- NOI Linux 2.0的安装
- c语言猴子吃桃问题(简洁做法)
- Flash Socket 的基本通讯协议流程例子
- 2012服务器系统配置DNS,win服务器2012配置dns
- 2023年1月12日,openKylin 0.9.5正式发布!
- 正则匹配中文英文字符、数据及标点
- dict转json保存_14、序列化操作,类的保存和dict转JSON
- xml格式标注文件转csv格式