Android-Java卖票案例-推荐此方式Runnable
上一篇博客 Android-卖票案例static-不推荐此方式,讲解了卖票案例是 private static int ticket = 10;,static静态的这种方式来解决卖票多卖30张的问题,但并不推荐这种方式,因为还有更加合理的方式,那就不得不提到Runnable接口,此篇博客就是使用Runnable来解决卖票多卖30张的问题
需求描述:四个窗口一起卖票,把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张票
在main方法中,thread1.start();/thread2.start();/thread3.start();/thread4.start(); 四个线程去启动一个Runnable实现类Booking,ticket变量就是只有一个了
package android.java.thread07; /**
* 售票线程
*/
class Booking implements Runnable { /**
* 模拟票的总算 10张票
*/
private int ticket = 10; @Override
public void run() { while (ticket > 0) { if (ticket > 0) {
System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");
ticket--;
}
} }
} /**
* 售票案例
*/
public class BookingTest { public static void main(String[] args) { /**
* 定义Runnable实现类Booking,此实现类Booking不是线程,此实现类Booking给四个Thread去执行的
*/
Runnable booking = new Booking(); // 实例化线程对象
Thread thread1 = new Thread(booking); // 此实现类Booking给Thread去执行的
Thread thread2 = new Thread(booking); // 此实现类Booking给Thread去执行的
Thread thread3 = new Thread(booking); // 此实现类Booking给Thread去执行的
Thread thread4 = new Thread(booking); // 此实现类Booking给Thread去执行的 // 开启启动线程
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快速切换四个线程,导致重复卖票的问题,加同步synchronized
package android.java.thread07; /**
* 售票线程
*/
class Booking implements Runnable { /**
* 模拟票的总算 10张票
*/
private int ticket = 10; @Override
public void 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) { /**
* 定义Runnable实现类Booking,此实现类Booking不是线程,此实现类Booking给四个Thread去执行的
*/
Runnable booking = new Booking(); // 实例化线程对象
Thread thread1 = new Thread(booking); // 此实现类Booking给Thread去执行的
Thread thread2 = new Thread(booking); // 此实现类Booking给Thread去执行的
Thread thread3 = new Thread(booking); // 此实现类Booking给Thread去执行的
Thread thread4 = new Thread(booking); // 此实现类Booking给Thread去执行的 // 开启启动线程
thread1.start(); // 启动第Thread-0窗口 执行卖票任务
thread2.start(); // 启动第Thread-1窗口 执行卖票任务
thread3.start(); // 启动第Thread-2窗口 执行卖票任务
thread4.start(); // 启动第Thread-3窗口 执行卖票任务
} }
执行结果:已经满足需求
Android-Java卖票案例-推荐此方式Runnable的更多相关文章
- JUC 并发编程--01,线程,进程,经典卖票案例, juc的写法
进程: 就是一个程序, 里面包含多个线程, 比如一个QQ程序 线程: 进程中最小的调度单元, 比如 QQ中的自动保存功能 并发: 多个线程操作同一资源, 抢夺一个cpu的执行片段, 快速交替 并行: ...
- Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)
多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念.进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线 ...
- java多线程实现卖票小程序
package shb.java.demo; /** * 多线程测试卖票小程序. * @Package:shb.java.demo * @Description: * @author shaobn * ...
- Android-卖票案例static-不推荐此方式
需求描述:四个窗口一起卖票,把10张票卖完,不许多卖 先看一个错误的案例: package android.java.thread06; /** * 售票线程 */ class Booking ext ...
- java 多线程之卖票两种方式
1.通过extends Thread /* 需求:简单的卖票,多个窗口同时买票 (共用资源) 创建线程的第二种方式:实现Runnable接口 步骤: 1,定义类实现Runnable接口 2,覆盖/重写 ...
- Java线程同步(synchronized)——卖票问题
卖票问题通常被用来举例说明线程同步问题,在Java中,采用关键字synchronized关键字来解决线程同步的问题. Java任意类型的对象都有一个标志位,该标志位具有0,1两种状态,其开始状态为1, ...
- java学习多线程之卖票示例
这一节我们来说一个示例就是卖票示例: 需求: 我们现在有100张票,然后分四个窗口来卖,直到卖完为止. 思路: 1.先定一个一个票类,描述票的属性,还有打印卖出的票,并且实现Runnable中的run ...
- Java之多线程窗口卖票问题(Runnable)
/** * 例子:创建三个窗口卖票,总票数为100张.使用实现Runnable接口的方式 * 存在线程的安全问题,待解决. */class Window1 implements Runnable{ p ...
- Java之多线程窗口卖票问题(Thread)
/** * * 例子:创建三个窗口卖票,总票数为100张.使用继承Thread类的方式 * * 存在线程的安全问题,待解决. * */class Window extends Thread{ priv ...
随机推荐
- SmartOS技术常见问题
什么是默认用户名和密码? 当SmartOS Live Image第一次启动时,系统将提示您设置root密码. 如果在不导入Zpool的情况下启动SmartOS,则需要默认的root密码. 当使用noi ...
- dubbo hessian+dubbo协议
Dubbo缺省协议采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况 Hessian协议用于集成Hessian的服务,Hessian底层采 ...
- Maven(Eclipse版)
前言: 由于最近工作学习,总是能碰到Maven的源码.虽然平时工作并不使用Maven,但是为了学习一些源码,还是必须要了解下.这篇文章不是一个全面的Maven解析,而是一个简单的介绍,包括Eclips ...
- $(this).form("validate") 始终返回false
onsubmit 提交前触发,返回 false 来阻止提交动作. validate 进行表单字段验证,当全部字段都有效时返回 true .该方法和 validatebox 插件一起使用. 解决:注释掉 ...
- 表单input中disabled提交后得不到值的解决办
input 按钮的disabled属性,如果设置了,form表单提交后,后台接收不到input的value input的字段当为diabled时时无法获取数值得,所以最近不要用这个,我们可以用read ...
- for循环计算阶乘
int x = 10; for(int y = x - 1; y >= 1; y--) { x = x * y; } System.out.println(x); 从10乘到1的阶乘写法. lo ...
- Dubbo简单理解
Dubbo 致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案.简单的说,Dubbo就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的时候,才有Dubbo这样 ...
- Ubuntu中解决机箱前置耳机没声音
Ubuntu中解决机箱前置耳机没声音 安装pavucontrol软件: sudo apt-get install pavucontrol 然后直接运行pavucontrol打开软件: 将输出设备设置为 ...
- DOS中符号的英文对照
--------------siwuxie095 1..:point 或 dot 或 period 或 full stop 2.空格:space 或 blank ------------------- ...
- TZOJ 4813 机器翻译(模拟数组头和尾)
描述 小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章. 这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换.对于每个英文单词,软件会先在内存中查找这 ...