今天是我自学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_三个窗口同时卖火车票,如何用代码将该场景实现?相关推荐

  1. 卖票问题 - 三种解决方法

    目录 案例:卖票 出现的问题 解决方法: 方式一:同步代码块 方式二:同步方法 方式三:Lock锁 案例:卖票 /**例子:创建三个窗口卖票,总票数为100张.使用实现Runnable接口的方式* @ ...

  2. 【Java9】异常,finally,线程创建(卖票),线程同步(卖包子),线程练习

    文章目录 1.错误和异常区别:Arrays.toString(array) 2.编译和运行异常:SimpleDateFormat 3.处理异常:方法声明抛出 4.finally关键字:catch相当于 ...

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

    一.需求分析: 模拟卖票窗口,实现5个窗口同时卖100张票(代码为了截图采用30张票) 知识点:多线程,锁,多线程的安全问题,线程的生命周期 二.代码实现 public class TestSellT ...

  4. 如何高效实现多窗口卖票

    多窗口卖票是常见的多线程问题,来看看要怎么搞 方法1,不建议的使用方式 package concurrent.me.ticket;import java.util.ArrayList; import ...

  5. 哈尔滨火车站下面有三个火车票代售点,假如哈尔滨到北京的火车票总共是200张,如何用程序来实现三个售票点同时卖票的功能。

    題目內容: 哈尔滨火车站下面有三个火车票代售点,假如哈尔滨到北京的火车票总共是200张,如何用程序来实现三个售票点同时卖票的功能. 哈尔滨站卖了一张票,还剩9张票. 香坊站卖了一张票,还剩8张票. 哈 ...

  6. 多线程经典问题 卖票问题

    /** 需求:某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票 思路: ① 定义一个类Ticket实现Runnable接口,里面定义一个成员变量:pri ...

  7. 线程安全问题经典案例---卖票

      在入门多线程的时候,看到过不少的案例,其中卖票案例尤为经典,在这里自己也记录一下,同时加深对于线程安全的理解: 案例场景 情景一:    现在有一个电影院,马上要上映电影<战狼5>,电 ...

  8. 多线程:线程同步与死锁(卖票案例)、线程通信、生产者与消费者

    卖票案例 5个窗口同时卖票: 使用Runnable接口,只创建了一个ticket1对象,5个线程共享此对象,实现了资源共享. public class ticket1 implements Runna ...

  9. Java线程安全(卖票案例) 如何解决线程安全(synchronized ,显示锁Lock)

    文章目录 线程安全 解决方法: 1.同步代码块 2.同步方法 3.显示锁 显示锁与隐式锁的区别 4.公平锁与非公平锁 线程安全 经典问题:卖票问题,多个线程一起执行该任务,当余票只有1一张时,三个线程 ...

最新文章

  1. Android -- Messenger与Service
  2. java中String对象和String变量
  3. 英特尔图形学专家被AMD挖走,研发实时光追技术,从部门主管变成副总裁
  4. C++中流的基本概念
  5. 执行SQL-MapperProxy.invoke()
  6. 夜深人静,想规划一下短期
  7. 一个实时收集MySql变更记录的组件CanalSharp.AspNetCore
  8. input子系统基础之按键4——输入核心层源码分析
  9. java system类_Java System类mapLibraryName()方法及示例
  10. [java] DOS编译 .java 文件得到 .class 文件 并执行 以及使用外部 .jar包 时的命令...
  11. BZOJ3531-[Sdoi2014]旅行(树剖+线段树动态开点)
  12. ASCLL码表完整版
  13. NOI Linux 2.0的安装
  14. c语言猴子吃桃问题(简洁做法)
  15. Flash Socket 的基本通讯协议流程例子
  16. 2012服务器系统配置DNS,win服务器2012配置dns
  17. 2023年1月12日,openKylin 0.9.5正式发布!
  18. 正则匹配中文英文字符、数据及标点
  19. dict转json保存_14、序列化操作,类的保存和dict转JSON
  20. xml格式标注文件转csv格式

热门文章

  1. 三猿开泰,走进普通、文艺、2B程序猿的逗比世界
  2. 427. 建立四叉树
  3. javascript实现图片上传实时显示上传图片
  4. 被囊群优化算法(TSA)详解,附源码,直接可以
  5. 英语文档学习颗粒归仓
  6. 怀揣一颗赤子之心,他回国创业,逐步实现自己的产业梦
  7. 微信H5支付(V3)
  8. 前备 正点原子以及野火stm32资料获取
  9. AssetStudioGUI获取Unity游戏资源
  10. 张景明:方剂【方歌】——祛暑剂