需求描述:四个窗口一起卖票,把10张票卖完,不许多卖

先看一个错误的案例:

package android.java.thread06;

/**
* 售票线程
*/
class Booking extends Thread { /**
* 模拟票的总算 10张票
*/
private int ticket = 10; @Override
public void run() {
super.run(); while (ticket > 0) {
System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");
ticket -- ;
}
}
} /**
* 售票案例
*/
public class BookingTest { public static void main(String[] args) { // 实例化线程对象
Thread thread1 = new Booking();
Thread thread2 = new Booking();
Thread thread3 = new Booking();
Thread thread4 = new Booking(); // 开启启动线程
thread1.start(); // 启动第Thread-0窗口 执行卖票任务
thread2.start(); // 启动第Thread-1窗口 执行卖票任务
thread3.start(); // 启动第Thread-2窗口 执行卖票任务
thread4.start(); // 启动第Thread-3窗口 执行卖票任务
} }

日志结果:

名称:Thread-0窗口卖出第10张票
名称:Thread-0窗口卖出第9张票
名称:Thread-0窗口卖出第8张票
名称:Thread-1窗口卖出第10张票
名称:Thread-0窗口卖出第7张票
名称:Thread-0窗口卖出第6张票
名称:Thread-0窗口卖出第5张票
名称:Thread-0窗口卖出第4张票
名称:Thread-0窗口卖出第3张票
名称:Thread-0窗口卖出第2张票
名称:Thread-0窗口卖出第1张票
名称:Thread-1窗口卖出第9张票
名称:Thread-1窗口卖出第8张票
名称:Thread-1窗口卖出第7张票
名称:Thread-1窗口卖出第6张票
名称:Thread-1窗口卖出第5张票
名称:Thread-1窗口卖出第4张票
名称:Thread-1窗口卖出第3张票
名称:Thread-1窗口卖出第2张票
名称:Thread-2窗口卖出第10张票
名称:Thread-2窗口卖出第9张票
名称:Thread-1窗口卖出第1张票
名称:Thread-2窗口卖出第8张票
名称:Thread-2窗口卖出第7张票
名称:Thread-3窗口卖出第10张票
名称:Thread-3窗口卖出第9张票
名称:Thread-2窗口卖出第6张票
名称:Thread-3窗口卖出第8张票
名称:Thread-3窗口卖出第7张票
名称:Thread-2窗口卖出第5张票
名称:Thread-3窗口卖出第6张票
名称:Thread-2窗口卖出第4张票
名称:Thread-3窗口卖出第5张票
名称:Thread-2窗口卖出第3张票
名称:Thread-3窗口卖出第4张票
名称:Thread-2窗口卖出第2张票
名称:Thread-2窗口卖出第1张票
名称:Thread-3窗口卖出第3张票
名称:Thread-3窗口卖出第2张票
名称:Thread-3窗口卖出第1张票

从日志结果来看,没有实现需求,反而多卖了30张,例如:本来一节车厢坐10人,结果一节车厢卖了40张票,这是非常严重的错误

为什么会这样呢,看内存图就明白了:

由于 Thread-0线程有自己的ticket变量

   Thread-1线程有自己的ticket变量

   Thread-2线程有自己的ticket变量

   Thread-3线程有自己的ticket变量

    所以才会造成40张票


使用static:把ticket定义为static变量,ticket会跑到静态区,ticket就被四个线程对象共用

package android.java.thread06;

/**
* 售票线程
*/
class Booking extends Thread { /**
* 模拟票的总算 10张票 (定义静态变量,此变量会跑到静态区域,成为公用变量)
*/
private static int ticket = 10; @Override
public void run() {
super.run(); while (ticket > 0) {
System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");
ticket -- ;
}
}
} /**
* 售票案例
*/
public class BookingTest { public static void main(String[] args) { // 实例化线程对象
Thread thread1 = new Booking();
Thread thread2 = new Booking();
Thread thread3 = new Booking();
Thread thread4 = new Booking(); // 开启启动线程
thread1.start(); // 启动第Thread-0窗口 执行卖票任务
thread2.start(); // 启动第Thread-1窗口 执行卖票任务
thread3.start(); // 启动第Thread-2窗口 执行卖票任务
thread4.start(); // 启动第Thread-3窗口 执行卖票任务
} }

结果出现相同的票,这是CPU非常非常快速切换造成的:

结果只出现了 Thread-0  和 Thread-1 那是因为 Thread-0 已经把ticket-- 到 0了,所以无法其他的线程对象无法进入while循环,也就无法看到打印


解决CPU快速切换四个线程,导致重复卖票的问题,加同步

package android.java.thread06;

/**
* 售票线程
*/
class Booking extends Thread { /**
* 模拟票的总算 10张票 (定义静态变量,此变量会跑到静态区域,成为公用变量)
*/
private static int ticket = 10; @Override
public void run() {
super.run(); while (ticket > 0) { /**
* 加入同步标识,进行拦截,例如:我在ticket-- =9 的时候 其他线程不准ticket-- =9,这样就解决了重复--值的问题
*/
synchronized (Booking.class) {
/**
* 必须在同步里面再次判断 ticket > 0 , 因为CUP对四个线程切换太快 有可能ticket=-1 或 ticket=-2 ... ,所以必须再次判断
*/
if (ticket > 0) {
System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");
ticket--;
}
}
} }
} /**
* 售票案例
*/
public class BookingTest { public static void main(String[] args) { // 实例化线程对象
Thread thread1 = new Booking();
Thread thread2 = new Booking();
Thread thread3 = new Booking();
Thread thread4 = new Booking(); // 开启启动线程
thread1.start(); // 启动第Thread-0窗口 执行卖票任务
thread2.start(); // 启动第Thread-1窗口 执行卖票任务
thread3.start(); // 启动第Thread-2窗口 执行卖票任务
thread4.start(); // 启动第Thread-3窗口 执行卖票任务
} }

执行结果:已经满足需求

Android-卖票案例static-不推荐此方式的更多相关文章

  1. Android-Java卖票案例-推荐此方式Runnable

    上一篇博客 Android-卖票案例static-不推荐此方式,讲解了卖票案例是 private static int ticket = 10;,static静态的这种方式来解决卖票多卖30张的问题, ...

  2. JUC 并发编程--01,线程,进程,经典卖票案例, juc的写法

    进程: 就是一个程序, 里面包含多个线程, 比如一个QQ程序 线程: 进程中最小的调度单元, 比如 QQ中的自动保存功能 并发: 多个线程操作同一资源, 抢夺一个cpu的执行片段, 快速交替 并行: ...

  3. Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)

    多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念.进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线 ...

  4. Java多线程卖票例子

    package com.test; public class SaleTickets implements Runnable { private int ticketCount = 10;// 总的票 ...

  5. java多线程实现卖票小程序

    package shb.java.demo; /** * 多线程测试卖票小程序. * @Package:shb.java.demo * @Description: * @author shaobn * ...

  6. Java线程同步(synchronized)——卖票问题

    卖票问题通常被用来举例说明线程同步问题,在Java中,采用关键字synchronized关键字来解决线程同步的问题. Java任意类型的对象都有一个标志位,该标志位具有0,1两种状态,其开始状态为1, ...

  7. Java多线程练习:ticket卖票程序

    /*需求:简单的卖票程序多个窗口买票 */ class Ticket extends Thread{    private static int tick=100;    public void ru ...

  8. java学习多线程之卖票示例

    这一节我们来说一个示例就是卖票示例: 需求: 我们现在有100张票,然后分四个窗口来卖,直到卖完为止. 思路: 1.先定一个一个票类,描述票的属性,还有打印卖出的票,并且实现Runnable中的run ...

  9. java 多线程之卖票两种方式

    1.通过extends Thread /* 需求:简单的卖票,多个窗口同时买票 (共用资源) 创建线程的第二种方式:实现Runnable接口 步骤: 1,定义类实现Runnable接口 2,覆盖/重写 ...

随机推荐

  1. python的range函数与切片操作符

    range(start,stop,step)参数含义:start:计数从start开始.默认是从0开始.例如range(5)等价于range(0, 5);end:计数到end结束,但不包括end.例如 ...

  2. keras—多层感知器MLP—MNIST手写数字识别

    一.手写数字识别 现在就来说说如何使用神经网络实现手写数字识别. 在这里我使用mind manager工具绘制了要实现手写数字识别需要的模块以及模块的功能:  其中隐含层节点数量(即神经细胞数量)计算 ...

  3. In case of failure

    In case of failure http://acm.hdu.edu.cn/showproblem.php?pid=2966 Time Limit: 60000/30000 MS (Java/O ...

  4. anaconda+theano+keras手写字符识别新版

    标题介绍运行环境了win7 看网上好多keras识别minist 但是一般由于版本问题,无法直接用,,,这里还要特别感谢keras中文文档作者(三当家SCP).教程整的非常好.还有就是最好你在安装an ...

  5. Repeater嵌套Repeater

    <asp:Repeater ID="rptXiaoLei" runat="server" OnItemDataBound="rptXiaoLei ...

  6. 构建openssl debug版

    一.简介 作为一种安全协议,openssl囊括了主要的密码算法.常用的密钥和证书封装管理功能以及SSL协议,并提供了丰富的应用程序供测试或其它目的使用. 参考: http://www.linuxidc ...

  7. 767A Snacktower

    A. Snacktower time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...

  8. [SoapUI] 重载JSONComparator比对JSON Response,忽略小数点后几位,将科学计数法转换为普通数字进行比对,在错误信息中打印当前循环的case number及其他附加信息

    重载JSONComparator比对JSON Response,忽略小数点后几位,将科学计数法转换为普通数字进行比对,在错误信息中打印当前循环的case number及其他附加信息 package d ...

  9. Java数据结构和算法(一)树

    Java数据结构和算法(一)树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 前面讲到的链表.栈和队列都是一对一的线性结构, ...

  10. Oracle sql的基本优化写法和思路。

    首先简单介绍下常规的sql优化的方式: 1.肯定有人说建索引啊. 2.数据量实在太大,建分区啊. 3.其实基于目前公司的业务还有一种办法那就是向上聚集表.根据查询业务,专门抽取上来一张表,直接做到se ...