首先看题目描述:

假设有火车票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学习之路(多线程)---模拟售票(细解)的更多相关文章

  1. java学习之路--多线程实现的方法

    1 继承Thread类 继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Th ...

  2. java学习之路之javaSE基础1

    <h2>java学习之路之javaSE基础1</h2> <div> ###01.01_计算机基础知识(计算机概述)(了解)* A:什么是计算机?计算机在生活中的应用 ...

  3. 新篇章之我的java学习之路下

    昨天写下了人生的第一篇博客,今天接着写我的java学习之路有关开发及框架的学习过程. 想要学好java语言,只学习一些java的基本语法对实际开发中的用处还是不大的,所以我们还要掌握一些有关javaW ...

  4. java学习之路之javaSE基础2

    java学习之路之javaSE基础2 所有的代码都是引用他人写的. 1.逻辑运算符 //&,|,^,! //int x = 10; //5 < x < 15 //x > 5 ...

  5. Java学习之路(转)

    Java学习之路(书籍推荐)   一.基础类 1.<Thinking in java>(阅读2遍),入门第一位是建立正确的概念 2.<Core Java>这本书更贴近实践,更多 ...

  6. JAVA学习之路与大家分享

    这是我四年以前总结的JAVA学习之路,希望对初学者或想从事JAVA开发的人有帮助. 本人是软件工程专业出身,先后学过C.C++.JAVA.VB.delphi等等开发语言以及网络相关管理技术.哎,好久不 ...

  7. Java 学习之路 -- day00

    Java 学习之路 -- day00 Typora 快捷键操作 标题:#+空格 2. *斜体* 3. **加粗** 4. **斜体加粗*** 5. ~~删除线~~ 6. > 引用 7. ···分 ...

  8. Java学习手记2——多线程

    一.线程的概念 CPU执行程序,就好比一个人在干事情一样,同一个时间你只能做一件事情,但是这样的效率实在是太低了,在你用电脑的时候,听歌就不能浏览网页,看电影就不能下载视频,你想想是不是很蛋疼. 所以 ...

  9. (转)如何学习Java技术?谈Java学习之路

    51CTO编者注:这篇文章已经是有数年“网龄”的老文,不过在今天看来仍然经典.如何学习Java?本篇文章可以说也是面对编程初学者的一篇指导文章,其中对于如何学习Java的步骤的介绍,很多也适用于开发领 ...

随机推荐

  1. “全栈2019”Java第三十六章:类

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  2. 模糊查询中Like的使用

    通配符: %. _ %:表示任意个或多个字符.可匹配任意类型和长度的字符 _:表示任意单个字符.匹配单个任意字符,它常用来限制表达式的字符长度语句:(可以代表一个中文字符) demo: //usern ...

  3. windows本地搭建nginx+php+mysql+redis环境详细步骤

    1.mysql的下载和安装 这个可参考我另外一篇文章:http://www.cnblogs.com/myIvan/p/9265645.html 2.php的下载和配置修改 下载地址:https://w ...

  4. 《[MySQL技术内幕:SQL编程》读书笔记

    <[MySQL技术内幕:SQL编程>读书笔记 2019年3月31日23:12:11 严禁转载!!! <MySQL技术内幕:SQL编程>这本书是我比较喜欢的一位国内作者姜承尧, ...

  5. 大数据平台-修改主机名及ssh免密码登录

    一.查看服务器初始配置: 1.总核数 = 物理CPU个数 X 每颗物理CPU的核数 2.总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数 # 查看物理CPU个数cat /pr ...

  6. TD-LTE技术原理与系统设计

    王映民 等.人邮2010 E-UTRAN E-NodeB 无线资源管理承载 路由到SGW IP头压缩加密 UE附着MME选择 寻呼 广播 测量 EPC SGW 移动性管理  路由转发 终止寻呼 监听 ...

  7. Mastache.js学习笔记(转自小花喵)

    简单的记录我使用Mastache的使用. 为什么使用JS模板引擎? 当数据结构复杂,Js的拼接凌乱,难以维护,但是又需要通过ajax加载数据的时候: 而Mastache的上手难度不高,并符合大部分业务 ...

  8. 小米MIX 3获得ROOT权限的步骤

    小米MIX 3有没有办法开启Root超级权限?大伙都知道,Android设备有Root超级权限,一旦手机开启root相关权限,可以实现更强大的功能,比如大伙部门的营销部门的妹纸,使用一些营销工具都需要 ...

  9. docker jenkins使用(二)

    jenkins的安装很简单,但是jenkins的初次使用却很头疼.对于小白来说有点不太明白 背景: 开发更新app需要很多步骤,生成jar包.上传服务器.更新启动程序,如果有很多服务器,那么需要做好多 ...

  10. linux curl post/put请求

    案列: -X: 请求方式 --header: 请求header -d: 请求的数据 最后跟上请求的地址 curl -X PUT --header 'Content-Type: application/ ...