多线程实现多个窗口卖票问题

tw3.setName(“窗口3”);

tw1.start();

tw2.start();

tw3.start();

}

}

代码执行结果:

窗口1卖出了第30张票,剩余29张票

窗口1卖出了第29张票,剩余28张票

窗口1卖出了第28张票,剩余27张票

窗口1卖出了第27张票,剩余26张票

窗口1卖出了第26张票,剩余25张票

窗口1卖出了第25张票,剩余24张票

窗口1卖出了第24张票,剩余23张票

窗口1卖出了第23张票,剩余22张票

窗口1卖出了第22张票,剩余21张票

窗口1卖出了第21张票,剩余20张票

窗口1卖出了第20张票,剩余19张票

窗口1卖出了第19张票,剩余18张票

窗口1卖出了第18张票,剩余17张票

窗口1卖出了第17张票,剩余16张票

窗口1卖出了第16张票,剩余15张票

窗口1卖出了第15张票,剩余14张票

窗口1卖出了第14张票,剩余13张票

窗口1卖出了第13张票,剩余12张票

窗口1卖出了第12张票,剩余11张票

窗口1卖出了第11张票,剩余10张票

窗口1卖出了第10张票,剩余9张票

窗口1卖出了第9张票,剩余8张票

窗口1卖出了第8张票,剩余7张票

窗口1卖出了第7张票,剩余6张票

窗口1卖出了第6张票,剩余5张票

窗口1卖出了第5张票,剩余4张票

窗口1卖出了第4张票,剩余3张票

窗口1卖出了第3张票,剩余2张票

窗口1卖出了第2张票,剩余1张票

窗口1卖出了第1张票,剩余0张票

窗口1余票不足,停止售票!

窗口3卖出了第30张票,剩余29张票

窗口3卖出了第29张票,剩余28张票

窗口3卖出了第28张票,剩余27张票

窗口3卖出了第27张票,剩余26张票

窗口3卖出了第26张票,剩余25张票

窗口3卖出了第25张票,剩余24张票

窗口3卖出了第24张票,剩余23张票

窗口3卖出了第23张票,剩余22张票

窗口3卖出了第22张票,剩余21张票

窗口3卖出了第21张票,剩余20张票

窗口3卖出了第20张票,剩余19张票

窗口3卖出了第19张票,剩余18张票

窗口3卖出了第18张票,剩余17张票

窗口3卖出了第17张票,剩余16张票

窗口3卖出了第16张票,剩余15张票

窗口3卖出了第15张票,剩余14张票

窗口3卖出了第14张票,剩余13张票

窗口3卖出了第13张票,剩余12张票

窗口3卖出了第12张票,剩余11张票

窗口3卖出了第11张票,剩余10张票

窗口3卖出了第10张票,剩余9张票

窗口3卖出了第9张票,剩余8张票

窗口3卖出了第8张票,剩余7张票

窗口3卖出了第7张票,剩余6张票

窗口3卖出了第6张票,剩余5张票

窗口3卖出了第5张票,剩余4张票

窗口3卖出了第4张票,剩余3张票

窗口3卖出了第3张票,剩余2张票

窗口3卖出了第2张票,剩余1张票

窗口3卖出了第1张票,剩余0张票

窗口3余票不足,停止售票!

窗口2卖出了第30张票,剩余29张票

窗口2卖出了第29张票,剩余28张票

窗口2卖出了第28张票,剩余27张票

窗口2卖出了第27张票,剩余26张票

窗口2卖出了第26张票,剩余25张票

窗口2卖出了第25张票,剩余24张票

窗口2卖出了第24张票,剩余23张票

窗口2卖出了第23张票,剩余22张票

窗口2卖出了第22张票,剩余21张票

窗口2卖出了第21张票,剩余20张票

窗口2卖出了第20张票,剩余19张票

窗口2卖出了第19张票,剩余18张票

窗口2卖出了第18张票,剩余17张票

窗口2卖出了第17张票,剩余16张票

窗口2卖出了第16张票,剩余15张票

窗口2卖出了第15张票,剩余14张票

窗口2卖出了第14张票,剩余13张票

窗口2卖出了第13张票,剩余12张票

窗口2卖出了第12张票,剩余11张票

窗口2卖出了第11张票,剩余10张票

窗口2卖出了第10张票,剩余9张票

窗口2卖出了第9张票,剩余8张票

窗口2卖出了第8张票,剩余7张票

窗口2卖出了第7张票,剩余6张票

窗口2卖出了第6张票,剩余5张票

窗口2卖出了第5张票,剩余4张票

窗口2卖出了第4张票,剩余3张票

窗口2卖出了第3张票,剩余2张票

窗口2卖出了第2张票,剩余1张票

窗口2卖出了第1张票,剩余0张票

窗口2余票不足,停止售票!

通过代码执行结果可以看出,在运行的过程中出现了错误。因为窗口总共有30张票,可是窗口1、窗口2、窗口3各自卖出了30张票,等于卖出去90张票,说明车票没有共享。

解决继承Thread类,线程不共享数据的问题

为了解决车票没有共享的问题,我们需要加static关键字,将车票声明为静态变量,让三个售票窗口线程共享车票。

class TicketWindow extends Thread {

// 车票数量

private static int ticket = 30;

@Override

public void run() {

while (true) {

if (ticket > 0) {

System.out.println(Thread.currentThread().getName() + “卖出了第” + ticket-- + “张票,” + “剩余” + ticket + “张票”);

} else {

System.out.println(Thread.currentThread().getName() + “余票不足,停止售票!”);

break;

}

}

}

}

public class SellTicketTest1 {

public static void main(String[] args) {

TicketWindow tw1 = new TicketWindow();

TicketWindow tw2 = new TicketWindow();

TicketWindow tw3 = new TicketWindow();

tw1.setName(“窗口1”);

tw2.setName(“窗口2”);

tw3.setName(“窗口3”);

tw1.start();

tw2.start();

tw3.start();

}

}

代码执行结果:

窗口1卖出了第30张票,剩余29张票

窗口1卖出了第28张票,剩余27张票

窗口1卖出了第27张票,剩余26张票

窗口1卖出了第26张票,剩余25张票

窗口1卖出了第25张票,剩余24张票

窗口2卖出了第29张票,剩余28张票

窗口2卖出了第22张票,剩余21张票

窗口2卖出了第21张票,剩余20张票

窗口2卖出了第20张票,剩余19张票

窗口2卖出了第19张票,剩余18张票

窗口3卖出了第23张票,剩余22张票

窗口3卖出了第17张票,剩余16张票

窗口3卖出了第16张票,剩余15张票

窗口3卖出了第15张票,剩余14张票

窗口3卖出了第14张票,剩余13张票

窗口3卖出了第13张票,剩余12张票

窗口3卖出了第12张票,剩余11张票

窗口3卖出了第11张票,剩余10张票

窗口3卖出了第10张票,剩余9张票

窗口3卖出了第9张票,剩余8张票

窗口3卖出了第8张票,剩余7张票

窗口3卖出了第7张票,剩余6张票

窗口3卖出了第6张票,剩余5张票

窗口3卖出了第5张票,剩余4张票

窗口3卖出了第4张票,剩余3张票

窗口3卖出了第3张票,剩余2张票

窗口3卖出了第2张票,剩余1张票

窗口3卖出了第1张票,剩余0张票

窗口3余票不足,停止售票!

窗口1卖出了第24张票,剩余23张票

窗口1余票不足,停止售票!

窗口2卖出了第18张票,剩余17张票

窗口2余票不足,停止售票!

2.使用实现Runnable接口的方式

一个类通过继承Thread来实现多线程的话,则不适合多个线程共享资源,而通过实现Runnable就可以做到这一点。

class TicketWindow2 implements Runnable {

private int ticket = 30;

@Override

public void run() {

while (true) {

if (ticket > 0) {

System.out.println(Thread.currentThread().getName() + “卖出了第” + ticket-- + “张票,” + “剩余” + ticket + “张票”);

} else {

System.out.println(Thread.currentThread().getName() + “余票不足,停止售票!”);

break;

}

}

}

}

public class SellTicketTest2 {

public static void main(String[] args) {

TicketWindow2 tw = new TicketWindow2();

for (int i = 1; i < 4; i++) {

Thread t = new Thread(tw,“窗口”+i);

t.start();

}

}

}

为了节省篇幅,这儿不再展示测试结果!

第二种方式不需要加static关键字把车票声明为静态的,也实现了数据共享的问题。

实现Runnable接口的方式创建多线程,只产生了一个TicketWindow2对象,一个对象里边有一个属性,这样三个线程同时在操作一个属性,运行同一个run方法。

在实际开发中,推荐使用第二种方式。

以上两种方式存在线程安全问题:

打印车票时,会出现重票和错票。造成这个问题的原因是一个线程在操作共享数据过程中,未执行完毕的情况下,另外的线程参与进来,导致共享数据存在安全问题。

如何解决:

当线程1在操作ticket的时候,其他线程不能参与进来。直到线程1操作完ticket时,其他线程才可以开始操作ticket。这种情况即使线程1出现了阻塞,也不能被改变。

在Java中,我们通过同步机制,来解决线程的安全问题。

3.解决卖票过程中的线程安全问题

在这篇博客中,使用了同步方法的方式解决了线程安全问题。

代码实现:

class TicketWindow3 implements Runnable{

private static int ticket = 30;

@Override

public void run() {

while (true) {

synchronized (this) {

if (ticket > 0) {

try {

// 线程出现阻塞

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

读者福利

由于篇幅过长,就不展示所有面试题了,感兴趣的小伙伴

35K成功入职:蚂蚁金服面试Java后端经历!「含面试题+答案」

35K成功入职:蚂蚁金服面试Java后端经历!「含面试题+答案」

35K成功入职:蚂蚁金服面试Java后端经历!「含面试题+答案」

更多笔记分享

35K成功入职:蚂蚁金服面试Java后端经历!「含面试题+答案」
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
义、实战项目、讲解视频,并且会持续更新!**

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

读者福利

由于篇幅过长,就不展示所有面试题了,感兴趣的小伙伴

[外链图片转存中…(img-UssjfyvS-1713625120473)]

[外链图片转存中…(img-1dVYYo9j-1713625120473)]

[外链图片转存中…(img-8XRjeWV6-1713625120473)]

更多笔记分享

[外链图片转存中…(img-opmXREd3-1713625120474)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 11
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值