JAVA学习之路(多线程)---模拟售票(细解)
首先看题目描述:
假设有火车票100张,创建4个线程模拟4个售票点,每100ms售出一张,打印出售票过程,格式如下:
窗口3:卖出第100张票
窗口4:卖出第99张票
............
............
简单的思路就是创建一个类,首先肯定要去继承Thread。开启线程,由于是4个窗口,肯定要开启4个线程。然后让每个线程去输出结果,也就是卖出去的票。这里很多人想不到如何让4个线程不打印重复的票。(比如4个线程都卖出去了第100张票,这显然是不合理的)。
看代码:
- package com.lesson.thread;
- public class MyThread {
- public static void main(String[] args) {
- Ticket sell1 = new Ticket();
- Ticket sell2 = new Ticket();
- Ticket sell3 = new Ticket();
- Ticket sell4 = new Ticket();
- sell1.setName("窗口1");
- sell2.setName("窗口2");
- sell3.setName("窗口3");
- sell4.setName("窗口4");
- sell1.start();
- sell2.start();
- sell3.start();
- sell4.start();
- }
- }
- class Ticket extends Thread {
- private static int tickets = 100;//这里设置成static,目的是让每个线程共享这个变量。以免出现重复打印的现象。
- @Override
- public void run() {
- while(true) {
- if(tickets <= 0) {
- break;
- }
- 29 System.out.println(getName()+":买出第"+tickets--+"张票。");//卖出一张减一张票
- }
- }
- }
可能你已经看到了你想要的结果了。但是,还没完。目前代码写到这里是有问题的!!!
为什么?
看下面的代码:
- package thread;
- public class Mythread {
- public static void main(String[] args) {
- Ticket sell1 = new Ticket();
- Ticket sell2 = new Ticket();
- Ticket sell3 = new Ticket();
- Ticket sell4 = new Ticket();
- sell1.setName("窗口1");
- sell2.setName("窗口2");
- sell3.setName("窗口3");
- sell4.setName("窗口4");
- sell1.start();
- sell2.start();
- sell3.start();
- sell4.start();
- }
- }
- class Ticket extends Thread {
- private static int tickets = 100;
- @Override
- public void run() {
- while(true) {
- if(tickets <= 0) {
- break;
- }
- try {
- Thread.sleep(10); //让进来的线程睡10ms;线程1,2,3,4都睡在这
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(getName()+":买出了第"+tickets--+"张票。");
- }
- }
- }
与开始的代码不同在于让进来的线程睡一会。可以看到如下运行结果:
窗口2:买出了第0张票。
窗口3:买出了第-1张票。
窗口1:买出了第-2张票。
这里编者调出来了出问题的地方。可以看到怎么会第0,-1,-2张票???
做出解释:
其实在这里让线程睡一会就是为了演示这里有很多行代码要执行。假设票已经卖到第1张了,也就是tickets=1,然后第一条线程进来判断 tickets <= 0 ?不成立,然后线程1要睡 10ms,紧接着,线程2进来,这时 tickets 还是为1,因为线程1在睡,tickets 没有减 。然后线程2判断 tickets <= 0 ? 还是不成立,线程2又开始睡。同样,线程3,线程4都睡了。 这时的tickets 还是等于1的。然后线程1先醒过来,开始输出结果,tickets 减了1。可是这是其他的线程还是经过while里面的判断语句进来了的,只是睡了。所以当其他线程醒过来的时候,还是会打印出结果的。也就出现了上面的问题。
解决方法:
多线程并发改变同一变量,为了解决,采用同步代码块synchronized。里面加任意的对象,但是不能加this,因为这里创建了四个线程,每一个线程都有自己的对象,所以是四个不同的对象,没有用。所以这里不能用this,必须锁在同一个对象里才行。而Thickets.class这是唯一的。
- package thread;
- public class Mythread {
- public static void main(String[] args) {
- Ticket sell1 = new Ticket();
- Ticket sell2 = new Ticket();
- Ticket sell3 = new Ticket();
- Ticket sell4 = new Ticket();
- sell1.setName("窗口1");
- sell2.setName("窗口2");
- sell3.setName("窗口3");
- sell4.setName("窗口4");
- sell1.start();
- sell2.start();
- sell3.start();
- sell4.start();
- }
- }
- class Ticket extends Thread {
- private static int tickets = 100;
- @Override
- public void run() {
- while(true) {
- synchronized (Ticket.class) {//同步代码块
- if(tickets <= 0) {
- break;
- }
- try {
- Thread.sleep(100); //每100ms卖出一张
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(getName()+":买出了第"+tickets--+"张票。");
- }
- }
- }
- }
JAVA学习之路(多线程)---模拟售票(细解)的更多相关文章
- java学习之路--多线程实现的方法
1 继承Thread类 继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Th ...
- java学习之路之javaSE基础1
<h2>java学习之路之javaSE基础1</h2> <div> ###01.01_计算机基础知识(计算机概述)(了解)* A:什么是计算机?计算机在生活中的应用 ...
- 新篇章之我的java学习之路下
昨天写下了人生的第一篇博客,今天接着写我的java学习之路有关开发及框架的学习过程. 想要学好java语言,只学习一些java的基本语法对实际开发中的用处还是不大的,所以我们还要掌握一些有关javaW ...
- java学习之路之javaSE基础2
java学习之路之javaSE基础2 所有的代码都是引用他人写的. 1.逻辑运算符 //&,|,^,! //int x = 10; //5 < x < 15 //x > 5 ...
- Java学习之路(转)
Java学习之路(书籍推荐) 一.基础类 1.<Thinking in java>(阅读2遍),入门第一位是建立正确的概念 2.<Core Java>这本书更贴近实践,更多 ...
- JAVA学习之路与大家分享
这是我四年以前总结的JAVA学习之路,希望对初学者或想从事JAVA开发的人有帮助. 本人是软件工程专业出身,先后学过C.C++.JAVA.VB.delphi等等开发语言以及网络相关管理技术.哎,好久不 ...
- Java 学习之路 -- day00
Java 学习之路 -- day00 Typora 快捷键操作 标题:#+空格 2. *斜体* 3. **加粗** 4. **斜体加粗*** 5. ~~删除线~~ 6. > 引用 7. ···分 ...
- Java学习手记2——多线程
一.线程的概念 CPU执行程序,就好比一个人在干事情一样,同一个时间你只能做一件事情,但是这样的效率实在是太低了,在你用电脑的时候,听歌就不能浏览网页,看电影就不能下载视频,你想想是不是很蛋疼. 所以 ...
- (转)如何学习Java技术?谈Java学习之路
51CTO编者注:这篇文章已经是有数年“网龄”的老文,不过在今天看来仍然经典.如何学习Java?本篇文章可以说也是面对编程初学者的一篇指导文章,其中对于如何学习Java的步骤的介绍,很多也适用于开发领 ...
随机推荐
- 案例1-合并2个不同文件夹中的csv文件到另外一个目录,相同的文件名进行数据合并,不同的文件名直接移到新文件夹
发现在ubuntu和centos中有些命令还不一样,比如<<<可在centos中使用,但是ubuntu中不行 csv文件名以及格式如下 3669_20180121.csv 总笔数,2 ...
- 关于:maven项目中pom.xml文件添加依赖无法自动搜索的问题
用的是eclipse 1.Window------>Show View------->Maven Repositories(这个选项一般不直接显示,而在others里面) 2.操作完毕后会 ...
- LINQ -2015-04-27
LINQ--language-integrated-query 1.它和sql语言区别呢? SQL语言常用在ralational-database中,而LINQ对内存数据,数据库,xml文件等多种形式 ...
- HTML-★★★★★表单★★★★★
表单 <form id="" name="" method="post/get" action="负责处理的服务端" ...
- css 命名规划
命名规范 前言中略微描述了 CSS 怎么使用:下面介绍一下 CSS 的一些代码规范: CSS 命名一般采用小写英文单词或组合命名,单词与单词间以"-"分割:英文单词不缩写,除非一看 ...
- 由import javax.persistence.*;引用引发问题的思考(SpringBoot)
在学习SpringBoot的 JPA时候增加一个实体类的时候发现import包的时候一直报错. 对比一下,发现自己的项目里面是少了 spring-boot-starter-data-jpa.jar包的 ...
- python 获取文件路径
一种是获取当前你正在操作文件的路径 一种是获取你执行文件的路径(比如你在你调用的包里面更改了,执行的时候就不会找你的包的路径,而是你执行文件的路径)
- Angular material mat-icon 资源参考_Communication
ul,li>ol { margin-bottom: 0 } dt { font-weight: 700 } dd { margin: 0 1.5em 1.5em } img { height: ...
- final学习
类加载过程 1.装载:查找和导入Class文件 2.链接:其中解析步骤是可以选择的 (a)检查:检查载入的class文件数据的正确性 (b)准备:给类的静态变量分配存储空间 (c)解析:将符号引用转成 ...
- easyUI----纵向合并单元格
使用Easyui-DataGrid过程用.做统计/报表等时经常会使用到合并单元格,原生态Easyui-DataGrid没有合并单元格的属性或方法. 解决方案: 代码一 onLoadSuccess: f ...