java使用多线程模拟,售票,出现 剩余 -1张票的问题(元动力文档)

元动力的文档,中有一段代码,用synchronized关键字实现,两个线程同步卖票的问题,但是感觉那段代码,有些问题。

public class Ticket implements Runnable{

    private static final Object monitor = new Object();
    private static Integer COUNT = 100;

    String name;

    public Ticket(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        while (Ticket.COUNT > 0) {
            ThreadUtils.sleep(100);
            // 在这里加入了同步代码块
            synchronized (Ticket.monitor) {
                System.out.println(name + "出票一张,还剩" + Ticket.COUNT-- + "张!");
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Thread one = new Thread(new Ticket("一号窗口"));
        Thread two = new Thread(new Ticket("一号窗口"));
        one.start();
        two.start();
        Thread.sleep(10000);
    }
}

这是,原动力文档中的代码, 问题在 输出语句,输出时 使用了 Ticket.COUNT--, 后置减法。输出看起来没什么问题,最后会 还剩 0张票,这是 总共 10张票时,的结果,会发现它一共卖了 11次,即最后一次卖出后,还剩 -1 张。

 我自己写代码时,使用的是 先 COUNT--, 再输出,结果显示会 更合理一点,但是很明显 最后出现了 还剩 -1 张票。

public class TestSynchronized implements Runnable{

    // 加个锁
    //Object monitor = new Object(); // 这么 写,对这个对象加锁是不行的,因为每个实例,都会有这个对象
    static Object monitor = new Object();
    private static int TICKET_COUNT = 10;
    String name;

    public TestSynchronized(String name){
        this.name = name;
    }


    @Override
    public void run() {
        while (TICKET_COUNT > 0){
            try {
                Thread.sleep(100);
                synchronized (monitor){
                    TICKET_COUNT--;
                    /*
                    if(TestSynchronized.TICKET_COUNT == 0){
                        break;
                    }

                     */
                    System.out.println(name + "出票一张,还剩" + TICKET_COUNT + "张");
                }

            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void main(String args[]){
        Thread one = new Thread(new TestSynchronized(" 一号窗口"));
        Thread two = new Thread(new TestSynchronized("二号窗口"));
        one.start();
        two.start();
    }
}

个人理解:虽然我们在 代码逻辑中加了 COUNT_TICKET > 0的逻辑,但是加锁是 在循环内加的,假设 COUNT_TICKET = 1 时,两个线程都进入了循环,t1 抢到 了锁,将 COUNT_TICKET b变成 0, 释放锁后, t2 还是会 继续卖票,将 COUNT_TICKET 变成 -1。

感觉根本原因还是对于 共享变量COUNT_TICKET的访问, 发生在了加锁之前 ,),可以这么修改代码

while(true){
            try {
                Thread.sleep(100);
                synchronized (monitor){
                    if(TICKET_COUNT > 0){
                        TICKET_COUNT--;
                        System.out.println(name + "出票一张,还剩" + TICKET_COUNT + "张");
                    }else{
                        break;
                    }
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

另一中办法,在获取到锁后,还是要继续判断 COUNT_TICKET == 0。 将上面 我注释的 代码恢复,便可正常实现我们想要的逻辑。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值