多线程购票问题

购票问题

题目: 三个售票员 卖出 30张票

从购票问题入手,购票问题涉及到多线程并发问题,多线程同时访问卖票资源,怎么保证数据一致性是最重要的问题。

解决方案:

  1. 在方法上添加 synchronized 同步标志控制线程访问,一次只能有一个线程访问该方法。
  2. JDK1.5后提供的JUC(Java并发包)。

个人进行多线程编程按照三步骤:

	在高内聚低耦合的前提下:  线程-----操作-----资源类
	线程:创建线程对象
	操作:调用资源类对外暴露的调用方法
	资源类:线程操作的对象
Synchronized 同步

定义一个资源类,票数初始量和卖票方法,在卖票方法加上 Synchronized 同步标志。

class Ticket01{
    //30张票
    private int number = 30;
    //卖票
    public synchronized void saleTicket(){
        if(number > 0){
            System.out.println(Thread.currentThread().getName() + "\t卖出第" + (number--) + "票,还剩下" + number + "张");
        }
    }
}

Main方法

创建三个线程同时调用 Ticket01 类的卖票方法,输出结果如下:

public static void main(String[] args) {
    Ticket01 ticket = new Ticket01();
    //new Thread(Runable runable,String name)
    new Thread(new Runnable(){
        @Override
        public void run() {
            for (int i = 1; i <= 40; i++){
                ticket.saleTicket();
            }
        }
    }, "A").start();

    new Thread(new Runnable(){
        @Override
        public void run() {
            for (int i = 1; i <= 40; i++){
                ticket.saleTicket();
            }
        }
    }, "B").start();

    new Thread(new Runnable(){
        @Override
        public void run() {
            for (int i = 1; i <= 40; i++){
                ticket.saleTicket();
            }
        }
    }, "C").start();
}

由于线程抢占资源是随机的,每次调用的结果都是不同的。可以看出线程调用是有序的,说明 Synchronized 控制线程有序访问是成功的。

JUC

定义一个资源类,票数初始量和卖票方法,通过 JUC 提供的 Lock 接口和 ReentrantLock 实现类对方法进行加锁操作。

Lock 接口是 JUC 提供的锁接口,相比 Synchronized 同步功能更加强大,提供了更灵活的结构化,主要使用的实现类是 ReentrantLock 可重入锁。

class Ticket02{
    //30张票
    private int number = 30;
    //创建锁对象,可重入锁
    Lock lock = new ReentrantLock();
    //卖票
    public void saleTicket(){
        //加锁流程
        lock.lock();
        try {
            if(number > 0){
                System.out.println(Thread.currentThread().getName() + "\t卖出第" + (number--) + "票,还剩下" + number + "张");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}

Main方法

创建三个线程同时调用 Ticket02 类的卖票方法,输出结果如下:

public static void main(String[] args) {
    Ticket02 ticket = new Ticket02();
    //new Thread(Runable runable,String name)
    new Thread(() -> {for (int i = 1; i <= 20; i++)ticket.saleTicket();}, "A").start();
    new Thread(() -> {for (int i = 1; i <= 20; i++)ticket.saleTicket();}, "B").start();
    new Thread(() -> {for (int i = 1; i <= 20; i++)ticket.saleTicket();}, "C").start();
}

可以看出每个线程抢占资源后调用资源方法是有序的执行,Lock 也实现了多线程并发有序访问统一资源。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值