多线程卖票小案例

多线程卖票小案例

卖票

package cn.lucky.Thread;

/**
 * @author lucky
 */
public class Lucky_ticket_runnable implements Runnable{
    private static int num=50;

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            if(num>0){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+(--num)+"张");
            }

        }
    }
}

测试

package cn.lucky.Thread;

/**
 * @author lucky
 */
public class Test_tickets {
    public static void main(String[] args) {
        Lucky_ticket_runnable2 ltr = new Lucky_ticket_runnable2();
        Thread lt1 = new Thread(ltr,"lt1");
        Thread lt2 = new Thread(ltr,"lt2");
        Thread lt3 = new Thread(ltr,"lt3");
        lt1.start();
        lt2.start();
        lt3.start();
    }
}

​ 我们发现,出现了卖同一张票,以及卖票负数的情况,这是为什么呢?

  • 首先我们分析卖同一张票的原因
    • 其中--num我们可以理解为num=num-1;
    • 当A线程和B线程同时进入判断条件时,假设进入时票数num=30
    • A线程正在做num=这个过程,到这里阻塞了
    • 此时B线程正做num=这个过程
    • 此时如果不阻塞了,A线程开始做num-1,此时num=29
    • 此时B线程的已经执行num=这个过程,B线程的num=30,再执行num-1,B线程的结果也为29
    • 所以就出现了卖同一张票的过程
  • 然后我们分析超卖的情况
    • 当num=1的时候,由于线程抢占资源,A和B同时进入判断
    • 此时A线程做完输出语句--num,num的值为0
    • 而此时B线程还没执行输出语句,B中的num就变成了0
    • 然而B线程又要执行输出语--num,此时B中的num就变成了-1
    • 所以就出现了超卖的情况

那我们如何解决这个问题呢?

这个时候锁的概念就出现了

方式一:使用同步代码块

@Override
public void run() {
    for (int i = 0; i < 50; i++) {
        synchronized (this.getClass()){
            if(num>0){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+(--num)+"张");
            }
        }

    }
}

方式二:使用synchronized关键字

@Override
public synchronized void run() {
    for (int i = 0; i < 50; i++) {
            if(num>0){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+(--num)+"张");
            }
    }
}

方式三:使用锁机制

Lock l = new ReentrantLock();

@Override
public void run() {
    for (int i = 0; i < 50; i++) {
        //获取锁
        l.lock();
        try {
            if (num > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出一张票,剩余" + (--num) + "张");
                Thread.sleep(100);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放锁
            l.unlock();
        }
    }
}

结果

posted @ 2021-03-17 19:25  Lucky8991  阅读(177)  评论(0)    收藏  举报