概述:火车票20张,三个窗口同时卖火车票
一.创建一个Runnable接口的实现类TicketSell,重写run()方法
public class TicketSell implements Runnable{
private int count = 20; //票数20张
@Override
public void run() {
Thread thread = Thread.currentThread(); //使用Thread的静态方法获取当前Thread对象
while(true){
if(count>0){
try {
Thread.sleep(200); //相当于该线程被挂起,200ms后就绪再去抢占CPU运行
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getName()+" "+(--count));
}
}
}
}
二.创建测试类,main方法中,创建三个Thread对象(三个窗口);
package com.blueSky.TicketDemo;
public class TicketTest {
public static void main(String[] args) {
TicketSell ticketSell = new TicketSell(); //3个窗口同卖20张票,使用一个Runnable接口的实现类
//第一个窗口
Thread thread1 = new Thread(ticketSell);
thread1.setName("1号窗口");
thread1.start();
//第二个窗口
Thread thread2 = new Thread(ticketSell);
thread2.setName("2号窗口");
thread2.start();
//第三个窗口
Thread thread3 = new Thread(ticketSell);
thread3.setName("3号窗口");
thread3.start();
}
}
三.运行main方法进行测试
四 测试结果
![这里写图片描述](https://img-blog.csdn.net/20180209173511769?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvQmx1ZVNreUluTXlNaW5k/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
五 问题分析
出现负数的原因:
进入条件后发生冲突,共享数据
睡眠相当于该线程被挂起,暂停执行,
* 假设此时count=1,线程1抢到CPU执行, 进入条件体,线程1休息200ms,该线程未执行count-1操作,
* 所以下一个线程(比如线程3)抢到CPU执行时,count仍为1,仍会进入条件体,然后执行语句,睡眠200ms,
* 当线程2到时,若两个线程还在睡眠(即都未执行count-1操作),count仍为1,线程3执行条件体,睡眠200ms,
* 若之后线程1,睡眠时间到,且抢到了CPU执行,那么count-1 此时count=0
* 然后线程2,3睡眠时间到,线程3抢到了CPU执行,那么count-1 此时count=0-1=-1
* * 然后线程3抢到了CPU ,那么执行count-1 此时count=-1-1=-2
六 .问题解决
使用同步锁,
- 使用同步代码块
package com.blueSky.TicketDemo;
public class TicketSell implements Runnable{
private int count = 20; //票数20张
@Override
public void run() {
Thread thread = Thread.currentThread(); //使用Thread的静态方法获取当前Thread对象
while(true){
synchronized (this) { //同步锁,同步代码块要把共享变量包进去
if(count>0){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getName()+" "+(--count));
}
}
}
}
}
2 封装方法,方法上加synchronized修饰
package com.blueSky.TicketDemo;
public class TicketSell implements Runnable{
private int count = 20; //票数20张
@Override
public void run() {
Thread thread = Thread.currentThread(); //使用Thread的静态方法获取当前Thread对象
while(true){
// synchronized (this) {
ticketCount(thread); //封装方法,方法上加synchronized进行修饰
// }
}
}
private synchronized void ticketCount(Thread thread) { //方法上加synchronized进行修饰,该方法为同步方法,该方法同时只能有一个线程访问。
if(count>0){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getName()+" "+(--count));
}
}
}
七. 同步锁好坏
优点:线程安全
缺点:效率低 (就像开关门要消耗时间一样)