使用Java多线程模拟一个售票系统

1.基于继承Thread实现

代码实现:

/**
 * 多线程模拟售票,基于Thread
 */
public class TicketSalesByThread {
    public static void main(String[] args) {
        SellTicket sellTicket = new SellTicket();
        SellTicket sellTicket1 = new SellTicket();
        SellTicket sellTicket2 = new SellTicket();
        sellTicket.start();
        sellTicket1.start();
        sellTicket2.start();
    }
}


class SellTicket extends Thread {
    // 余票
    private static int ticketNum = 100;
    @Override
    public void run() {
        while (true) {
            if (ticketNum <= 0) {
                System.out.println("没有余票!");
                break;
            }
            // 休眠卖票
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("窗口" + Thread.currentThread().getName() +
                    "售出一张票。" + "剩余票数:" + (--ticketNum));
        }
    }
}

结果分析:

窗口Thread-1售出一张票。剩余票数:97
...
窗口Thread-2售出一张票。剩余票数:2
窗口Thread-0售出一张票。剩余票数:1
窗口Thread-1售出一张票。剩余票数:0
没有余票!
窗口Thread-2售出一张票。剩余票数:-1
没有余票!
窗口Thread-0售出一张票。剩余票数:-2
没有余票!

可以看到,基于Thread的实现,出现了明显的超卖现象!🦮

那么,为什么会发生这种情况呢?

原因分析:

当一个窗口还未执行--ticketNum操作时,另一个窗口已经进行售票状态,跳过了while循环的限制


2.基于实现Runnable接口实现

代码实现:

/**
 * 多线程模拟售票,基于实现Runnable接口
 */
public class TicketSalesByRunnable {
    public static void main(String[] args) {
        SellTicket02 sellTicket02 = new SellTicket02();
        new Thread(sellTicket02).start();
        new Thread(sellTicket02).start();
        new Thread(sellTicket02).start();
    }
}

class SellTicket02 implements Runnable {
    private int ticketNum = 100;
    @Override
    public void run() {
        while (true) {
            if (ticketNum <= 0) {
                System.out.println("没有余票!");
                break;
            }
            // 休眠卖票
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("窗口" + Thread.currentThread().getName() +
                    "售出一张票。" + "剩余票数:" + (--ticketNum));
        }
    }
}

结果分析:

窗口Thread-0售出一张票。剩余票数:99
...
窗口Thread-0售出一张票。剩余票数:2
窗口Thread-1售出一张票。剩余票数:1
窗口Thread-2售出一张票。剩余票数:0
没有余票!
窗口Thread-0售出一张票。剩余票数:-1
没有余票!
窗口Thread-1售出一张票。剩余票数:-2
没有余票!

仍然会有超卖现象发生!


3.通知线程退出

有时候,我们需要不同的线程可以相互控制对方的运行

可以采用通知线程中止来解决此类问题,比如我们简单实现一个demo,实现主线程通知中止其他线程的效果:

/**
 * 通知线程中止
 */
public class ThreadExit {
    public static void main(String[] args) throws InterruptedException {
        TTT ttt = new TTT();
        ttt.start();
        Thread.sleep(5000);
        // 主线程通知其他线程退出
        ttt.setLoop(false);
    }
}

class TTT extends Thread {
    // 控制变量
    private boolean loop = true;
    @Override
    public void run() {
        while (loop) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("TTT线程正在运行...");
        }
    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }
}

TTT线程会运行5秒,随后由主线程通知退出


4.解决超卖问题,线程同步机制

在多线程编程中,一些敏感数据不允许被多个线程同时访问,此时就可以使用同步访问技术,保证数据在同一时刻只能有一个线程访问,以保证数据的完整性

synchronized线程同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作🐕‍🦺

上成品代码:

/**
 * 使用同步机制解决售票问题的超卖现象
 */
public class TicketSalesResult {
    public static void main(String[] args) {
        SellTicketRes sellTicketRes = new SellTicketRes();
        new Thread(sellTicketRes).start();
        new Thread(sellTicketRes).start();
        new Thread(sellTicketRes).start();
    }
}

class SellTicketRes implements Runnable {
    private int ticketNum = 100;
    private boolean loop = true;

    /**
     * 使用synchronized实现线程同步,解决超卖
     */
    public synchronized void Sell() {
        if (ticketNum <= 0) {
            System.out.println("没有余票!");
            loop = false;
            return;
        }
        // 休眠卖票
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("窗口" + Thread.currentThread().getName() +
                "售出一张票。" + "剩余票数:" + (--ticketNum));
    }
    @Override
     public void run() {
        while (true) {
            if (loop == false) {
                break;
            }
            Sell();
        }
    }
}

结果分析:(完美解决超卖问题)

窗口Thread-0售出一张票。剩余票数:99
...
窗口Thread-2售出一张票。剩余票数:1
窗口Thread-2售出一张票。剩余票数:0
没有余票!
没有余票!
没有余票!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

世界尽头与你

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值