JAVA多线程案例——实现三个窗口卖票功能

news2024/12/22 20:02:40

一、需求分析

利用多线程的思想模拟三个窗口售票员卖30张票的功能:

我们采用线程对象来模拟售票窗口,实现多个窗口同时卖票, 采用 Runnable 接口子类来模拟票数

二、代码实现

1、继承 Thread 类的方式

class TicketWindow extends Thread {
    // 数量
    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 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();
    }
}
运行结果:

动图封面

通过代码执行结果可以看出,在运行的过程中出现了错误。因为窗口总共有 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();
    }
}
运行结果:

动图

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

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

通过实现 Runnable 接口,我们不需要加 static 关键字把车票声明为静态的,也可以实现数据共享。实现 Runnable 接口的方式创建多线程,只产生了一个 TicketWindow2 对象,一个对象里边有一个属性,这样三个线程同时在操作一个属性,运行同一个 run 方法。
在实际开发中,推荐使用实现 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();
        }
    }
}
以上两种方式存在线程安全问题:
打印车票时,会出现重票和错票。造成这个问题的原因是一个线程在操作共享数据过程中,未执行完毕的情况下,另外的线程参与进来,导致共享数据存在安全问题。
如何解决:
当线程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 {
                        // 线程出现阻塞
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket-- + "张票," + "剩余" + ticket + "张票");
                } else {
                    System.out.println(Thread.currentThread().getName() + "余票不足,停止售票!");
                    break;
                }
            }
        }
    }
}

public class SellTicketTest3 {
    public static void main(String[] args) {
        TicketWindow3 tw = new TicketWindow3();

        for (int i = 1; i < 4; i++) {
            Thread t = new Thread(tw,"窗口"+i);
            t.start();
        }
    }
}
运行结果:

动图

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/874320.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Unity】VS Code 没有智能提示 Unity 中的类

正常来说&#xff0c;VS Code中会对部分输入类名进行提示&#xff0c;如下图所述 假如你从Unity 中进入 VS Code后发现没有提示相关 Unity的类&#xff0c;可能是 Unity 中 有关于 VS Code的相关Package 没有跟着 VS Code升级到最新版本。 点击Unity Windows 下拉框中的 Pac…

分布式监控平台—zabbix

前言一、zabbix概述1.1 什么是zabbix1.2 zabbix的监控原理1.3 zabbix常见五个应用程序1.4 zabbix的监控模式1.5 监控架构1.5.1 C/S&#xff08;server—client&#xff09;1.5.2 server—proxy—client1.5.3 master—node—client 二、部署zabbix2.1 部署 zabbix server 端2.2 …

1.2 初识输入输出

博主介绍&#xff1a;爱打游戏的计算机专业学生 博主主页&#xff1a;夏驰和徐策 所属专栏&#xff1a;夏驰和徐策带你从零开始学C 前言&#xff1a; C语言并未定义任何输入输出 (IO) 语句&#xff0c;取而代之&#xff0c;包 含了一个全面的标准库 (standard library) 来 提…

分支语句与循环语句(2)

3.3 do...while()循环 3.3.1 do语句的语法&#xff1a; do 循环语句; while(表达式); 3.3.2执行流程图&#xff1a; 3.3.3 do语句的特点 循环至少执行一次&#xff0c;使用的场景有限&#xff0c;所以不是经常使用。 打印1-10的整数&#xff1a; #define _CRT_SECURE_NO_WA…

8年经验之谈 —— 如何做安全测试?

作为一名专业的安全测试人员&#xff0c;以下是一些关键步骤&#xff0c;可以帮助你更好地进行安全测试&#xff1a; 1. 了解应用程序: 深入了解应用程序的功能、架构和技术栈。这有助于你理解潜在的安全风险和漏洞。 2. 制定测试计划: 创建一个详细的测试计划&#xff0c;确…

【系统软件03】centos7安装和使用node-v18.16.0(centos7升级glibc 2.28)

【系统软件03】centos7安装和使用node-v18.16.0&#xff08;centos7升级glibc 2.28&#xff09; 前言&#xff1a;本文是解决node 18.16.0的依赖问题&#xff0c;具体的node安装流程&#xff0c;可以参考我的另外一篇文章。一、下载node v18.16.0二、下载glibc2.28&#xff08;…

如何轻松注册企业邮箱?快速掌握超简单的注册技巧!

随着互联网的发展&#xff0c;越来越多的企业开始使用电子邮件作为通信工具。企业邮箱不仅可以提高企业的工作效率&#xff0c;还可以使企业通信更加便捷、保密性更高。那么&#xff0c;企业邮箱怎么注册申请呢&#xff1f;下面我们来详细介绍一下。 第一步&#xff1a;选择邮箱…

百日筑基篇——python爬虫学习(一)

百日筑基篇——python爬虫学习&#xff08;一&#xff09; 文章目录 前言一、python爬虫介绍二、URL管理器三、所需基础模块的介绍1. requests2. BeautifulSoup1. HTML介绍2. 网页解析器 四、实操1. 代码展示2. 代码解释1. 将大文件划分为小的文件2. 获得结果页面的url3. 获取结…

第05天 SpringBoot自动配置原理

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a;每天一个知识点 ✨特色专栏&#xff1a…

数学分析:曲线曲面积分

这一章还是很重要的&#xff0c;可以看到为什么dt1^dt2和dt1dt2是一样的。 可以看到&#xff0c;核心还是黎曼和&#xff0c;我们把两种微分的黎曼和都列出来&#xff0c;并且证明两个相等&#xff0c;即可。 这里要注意&#xff0c;微分形式的积分&#xff0c;在黎曼和的情况…

【解析postman工具的使用(基础篇】

postman前端请求详解 主界面1.常见类型的接口请求1.1 查询参数的接口请求1.1.1 什么是查询参数?1.1.2 postman如何请求 1.2 ❤表单类型的接口请求1.2.1 复习下http请求1.2.2❤ 什么是表单 1.3 上传文件的表单请求1.4❤ json类型的接口请求 2. 响应接口数据分析2.1 postman的响…

解决校园网使用vmware桥接模式,虚拟机与物理机互相ping通,但是虚拟机ping不通百度的问题

遇到的问题 使用校园网时&#xff0c;桥接模式下&#xff0c;物理机可以ping通虚拟机&#xff0c;但是虚拟机ping不通主机 解决方法 在物理机中查看网络相关信息 ipconfig 修改虚拟机网卡信息 vim /etc/sysconfig/network-scripts/ifcfg-ens33 注意 /ifcfg-ens33需要根据…

理解ConcurrentSkipListMap(有点类似于并发的TreeMap)

是一个分层的结构。 从最上面开始查找&#xff0c;最后层层往下查。 插入和删除有可能会引起节点Level的变更。 key是有序的&#xff0c;因此可以看做是并发的TreeMap

Docker常规安装简介

Docker常规安装简介 1、总体步骤&#xff1a;服务端口映射 搜索镜像 拉取镜像 查看镜像 启动镜像 停止容器 移除容器 2、安装tomcat docker hub上面查找tomcat镜像 docker search tomcat 从docker hub上拉取tomcat镜像到本地 docker pull tomcat docker images查看是否有拉…

2023年国赛数学建模思路 - 案例:ID3-决策树分类算法

文章目录 0 赛题思路1 算法介绍2 FP树表示法3 构建FP树4 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 算法介绍 FP-Tree算法全称是FrequentPattern Tree算法&#xff0c;就是频繁模…

电机故障诊断(python程序,模型为MSCNN结合LSTM结合注意力机制模型,有注释)

代码运行环境要求&#xff1a;TensorFlow版本>2.4.0&#xff0c;python版本>3.6.0 1.电机常见的故障类型有以下几种&#xff1a; 轴承故障&#xff1a;轴承是电机运转时最容易受损的部件之一。常见故障包括磨损、疲劳、过热和润滑不良&#xff0c;这些问题可能导致噪音增…

97. Interleaving String 72. Edit Distance 121. 122. 123

​​​​​​97. Interleaving String 72. Edit Distance 一个bottomup&#xff08;棋盘从右下角外围逼近[0,0]&#xff09;如果横轴是string1的index i&#xff0c;纵轴string2的index j&#xff0c;那么&#xff0c;很奇妙的是i和j一起&#xff08;从右下角的格子看&#xf…

RTT(RT-Thread)IO设备模型

目录 IO设备模型 模型框架原理 IO设备类型 创建和注册IO设备 RTT设备管理程序实现原理 访问IO设备 查找设备 初始化设备 打开设备 关闭设备 控制设备 读写设备 数据收发回调 数据接收回调 数据发送回调 设备模型实例 IO设备模型 RT-Thread 提供了一套简单的 I/O …

穿透防线:泛微E-Office任意文件上传漏洞解析

子曰&#xff1a;“学天时习之&#xff0c;不亦说乎&#xff1f;有朋自远方来&#xff0c;不亦乐乎&#xff1f;人不知而不愠&#xff0c;不亦君子乎&#xff1f;” 漏洞复现 访问漏洞url&#xff1a; 构造漏洞利用payload ​POST /general/index/UploadFile.php?muploadP…

Kettle系列(二)smart-kettle本地离线部署

Kettle系列&#xff08;二&#xff09;smart-kettle本地离线部署 说明一、概述二、代码下载&#xff08;1&#xff09;后端代码依赖下载&#xff08;2&#xff09;前端代码依赖下载 三、创建数据库&#xff08;mysql8&#xff09;四、修改配置文件五、mysql8数据库配置六、其他…