多线程实现卖票

假设电影院正在上映某电影,该电影有100张电影票可供出售,现在假设有3个窗口售票。请设计程序模拟窗口售票的场景。

分析:

3个窗口互不影响,同时售票

3个窗口共同出售这100张电影票

下面是两种用多线程实现的方式,但是都有问题(会出现卖的票重复、卖不存在的票、票的顺序出错)

            部分运行结果

方式一

//方式一:将类声明为Thread的子类
public class Test {
    public static void main(String[] args) {
        //创建线程对象
        SellTicket t1 = new SellTicket();
        SellTicket t2 = new SellTicket();
        SellTicket t3 = new SellTicket();
        //各线程起名字
        t1.setName("一号窗口");
        t2.setName("二号窗口");
        t3.setName("三号窗口");
        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

class SellTicket extends Thread {
    static int ticket = 100;//初始有100张票
    @Override
    public void run() {
        while (ticket > 0) {//一直卖票,直到票卖完
            try {//模拟选中票后的网络延迟
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getName() + "卖了第" + ticket-- + "张票");
        }
    }
}

方式二 

//方式二:声明实现 Runnable 接口的类
public class Test {
    public static void main(String[] args) {
        //创建一个Runnable子类对象
        SellTicket myRunnable = new SellTicket();
        //创建多个线程并起名
        Thread t1 = new Thread(myRunnable, "一号窗口");
        Thread t2 = new Thread(myRunnable, "二号窗口");
        Thread t3 = new Thread(myRunnable, "三号窗口");
        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}
class SellTicket implements Runnable {
    int ticket = 100;//初始有100张票,
    //因为多个线程都是从同一个Runnable子类对象来的,可以共享这个普通成员变量
    @Override
    public void run() {
        while (ticket > 0) {//一直卖票,直到票卖完
            try {//模拟选中票后的网络延迟
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "卖了第" + ticket-- + "张票");
        }
    }
}

出错原因:

ticket--操作不是原子操作,它可以细分为三步:取值 、做-1运算、重新赋值,所以会因为线程切换导致不同结果。建议把像ticket这样的共享数据做锁对象处理

加锁后

方式二:声明实现 Runnable 接口的类
public class Test {
    public static void main(String[] args) {
        //创建一个Runnable子类对象
        SellTicket myRunnable = new SellTicket();
        //创建多个线程并起名
        Thread t1 = new Thread(myRunnable, "一号窗口");
        Thread t2 = new Thread(myRunnable, "二号窗口");
        Thread t3 = new Thread(myRunnable, "三号窗口");
        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}
class SellTicket implements Runnable {
    int ticket = 100;//初始有100张票,
    //因为多个线程都是从同一个Runnable子类对象来的,可以共享这个普通成员变量
    @Override
    public void run() {
        while (ticket > 0) {//一直卖票,直到票卖完
            synchronized (this) {
                try {//模拟选中票后的网络延迟
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "卖了第" + ticket-- + "张票");
            }
        }
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值