需求:某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票
思路:
①定义一个类 SellTicket实现 Runnable接口,里面定义一个成员变量: private int tickets=100
②在 SellTicket类中重写run()方法实现卖票,代码步骤如下
A:判断票数大于0,就卖票,并告知是哪个窗口卖的
B:卖了票之后,总票数要减1
C:票没有了,也可能有人来问,所以这里用死循环让卖票的动作一直执行
③定义一个测试类 SellTicketDemo,里面有main方法,代码步骤如下
A:创建 SellTicket类的对象
B:创建三个 Thread类的对象,把 SellTicket对象作为构造方法的参数,并给出对应的窗囗名称
C:启动线程
加个延迟:每次出票时间为100毫秒,用sleep()方法实现
/出现相同的票多次且出现负数的票,是由于随机性导致的/
package ysy11;
//定义一个类 SellTicket实现 Runnable接口,里面定义一个成员变量: private int tickets=100
public class SellTicket implements Runnable {
private int tickets = 100;
Object obj=new Object();
/* 在 SellTicket类中重写run()方法实现卖票,代码步骤如下
A:判断票数大于0,就卖票,并告知是哪个窗口卖的
B:卖了票之后,总票数要减1
C:票没有了,也可能有人来问,所以这里用死循环让卖票的动作一直执行*/
@Override
public void run() {
while (true) {
synchronized (obj) {
if (tickets > 0) {
//出票时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + tickets + "张票");
tickets--;
}
}
}
}
}
public class SellTicketDemo {
public static void main(String[] args) {
//创建 SellTicket类的对象
SellTicket st = new SellTicket();
//创建三个Thread类的对象,把 SellTicket对象作为构造方法的参数,并给出对应的窗囗名称
Thread t1=new Thread(st,"窗口A");
Thread t2=new Thread(st,"窗口B");
Thread t3=new Thread(st,"窗口C");
//启动线程
t1.start();
t2.start();
t3.start();
}
}
卖票案例数据安全问题的解决
为什么出现问题?这也是我们判断多线程程序是否会有数据安全问题的标准
- 是否是多线程环境
- 是否有共享数据
- 是否有多条语句操作共享数据
如何解决多线程安全问题呢? - 基本思想:让程序没有安全问题的环境
怎么实现呢? - 把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可
- java提供了同步代码块的方式解决
同步方法解决数据安全问题
package ysy11;
public class SellTicket implements Runnable {
private static int tickets = 100;
Object obj = new Object();
private int x = 0;
@Override
public void run() {
while (true) {
if (x % 2 == 0) {
synchronized (SellTicket.class) {
if (tickets > 0) {
//出票时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + tickets + "张票");
tickets--;
}
}
} else {
SellTicket();
}
x++;
}
}
public static synchronized void SellTicket() {
if (tickets > 0) {
//出票时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + tickets + "张票");
tickets--;
}
}
}