java runnable卖票_Android-Java卖票案例-推荐此方式Runnable

上一篇博客 Android-卖票案例static-不推荐此方式,讲解了卖票案例是 private static int ticket = 10;,static静态的这种方式来解决卖票多卖30张的问题,但并不推荐这种方式,因为还有更加合理的方式,那就不得不提到Runnable接口,此篇博客就是使用Runnable来解决卖票多卖30张的问题

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

先看一个错误的案例:

packageandroid.java.thread06;/*** 售票线程*/

class Booking extendsThread {/*** 模拟票的总算 10张票*/

private int ticket = 10;

@Overridepublic voidrun() {super.run();while (ticket > 0) {

System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");

ticket--;

}

}

}/*** 售票案例*/

public classBookingTest {public static voidmain(String[] args) {//实例化线程对象

Thread thread1 = newBooking();

Thread thread2= newBooking();

Thread thread3= newBooking();

Thread thread4= newBooking();//开启启动线程

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张票,这是非常严重的错误

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

ab2d3bda5e7817f9a6a7c2d837c97883.png

由于 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变量就是只有一个了

e0e57cc9583ba653b211d156c0ee682a.png

packageandroid.java.thread07;/*** 售票线程*/

class Booking implementsRunnable {/*** 模拟票的总算 10张票*/

private int ticket = 10;

@Overridepublic voidrun() {while (ticket > 0) {if (ticket > 0) {

System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");

ticket--;

}

}

}

}/*** 售票案例*/

public classBookingTest {public static voidmain(String[] args) {/*** 定义Runnable实现类Booking,此实现类Booking不是线程,此实现类Booking给四个Thread去执行的*/Runnable booking= newBooking();//实例化线程对象

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非常非常快速切换随机性造成的:

61a781c9b6740c0cff752ad974802513.png

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

e24d7ada7e46009a5c143424570b270b.png

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

packageandroid.java.thread07;/*** 售票线程*/

class Booking implementsRunnable {/*** 模拟票的总算 10张票*/

private int ticket = 10;

@Overridepublic voidrun() {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 classBookingTest {public static voidmain(String[] args) {/*** 定义Runnable实现类Booking,此实现类Booking不是线程,此实现类Booking给四个Thread去执行的*/Runnable booking= newBooking();//实例化线程对象

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窗口 执行卖票任务

}

}

执行结果:已经满足需求

057033df062c2401c5de4b95cd7e6f5f.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值