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 ...
随机推荐
- EasyUI多选的获取
function deletePRE() { var rows = $('#dg').datagrid('getSelections'); var ids = []; var other_ids = ...
- forward(请求转发)和redirect(重定向)的区别
原理: forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原 ...
- Js语言的奇怪特性
var a = .3 - 2; console.log(a); a = 0.099999998 而不是0.1,是不是很奇怪?
- TOYS(叉积)
TOYS http://poj.org/problem?id=2318 Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 193 ...
- MySQL优化update操作
http://www.cnblogs.com/jevo/p/3314928.html 用replace代替delete和insert. insert用批量. 用延迟(类似于缓冲,会否饿死) 大量插入, ...
- UVa 1595 Symmetry(set)
We call a figure made of points is left-right symmetric as it is possible to fold the sheet of paper ...
- python数据类型内部结构解剖
一.前言 我们知道,python是一种动态语言,可以将任何类型的数据赋给任何变量,譬如: # Python代码 x = 4 x = "four" 这里已经将 x 变量的内容由整型转 ...
- DB2与oracle类型对比
本文摘自http://www.cnblogs.com/cy163/archive/2010/11/17/1880280.html 做过DB2数据库应用迁移的工程师,了解IBM MTK工具在迁移过程中所 ...
- Jmeter发送某个request时而成功,时而失败(处理办法:失败的时候尝试重新发送这个HTTP request)
Jmeter发送某个request时而成功,时而失败 Maybe it’s Jmeter’s problem, after all, is not a commercial software. And ...
- 如何使用tapd?
tapd 可以编写测试用例 测试计划等 敏捷开发常用的工具.稍后会更新..