当出现 商品的销售量 > 实际的库存量 的现象 成为“超卖”
解释:假设某商品X卖剩下最后一件,线程A(客户)进来下单,下单完成,还没来得及减库存,这时线程B又进来了,判断还有库存,继续下单,这时出现超卖,库存实际有一件商品,却卖出了2件商品
package com.dj.springtest.demo;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* User: ldj
* Date: 2024/4/12
* Time: 19:08
* Description: 超卖测试
* (悲观锁synchronized)
* (乐观锁CAS: update tb_ticket set number = number - 1 where ticket_id = ? and number > 0)缺点不会走索引
*/
public class OversoldDemo {
public static void main(String[] args) {
Ticket ticket = new Ticket();
CountDownLatch countDownLatch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
countDownLatch.await();
//ticket.sale1();
//ticket.sale2();
ticket.sale3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "顾客" + i).start();
countDownLatch.countDown();
}
}
}
class Ticket {
//剩下最后一张票
private int tickets = 1;
//可重入锁(默认非公平,减少cpu来回切换的开销)
ReentrantLock reentrantLock = new ReentrantLock(true);
public void sale1() throws InterruptedException {
if (tickets > 0) {
//模拟还没来得及减库存
TimeUnit.SECONDS.sleep(2);
tickets = tickets - 1;
System.out.println("[" + Thread.currentThread().getName() + "]抢票成功" + "目前还剩" + tickets);
} else {
System.out.println("[" + Thread.currentThread().getName() + "]真抱歉!票已经售罄");
}
}
//集群部署情况还是会出现超卖现象,需要使用分布式锁
public synchronized void sale2() {
if (tickets > 0) {
tickets = tickets - 1;
System.out.println("[" + Thread.currentThread().getName() + "]抢票成功" + "目前还剩" + tickets);
} else {
System.out.println("[" + Thread.currentThread().getName() + "]真抱歉!票已经售罄");
}
}
//集群部署情况还是会出现超卖现象,需要使用分布式锁
public void sale3() {
reentrantLock.lock();
try {
if (tickets > 0) {
tickets = tickets - 1;
System.out.println("[" + Thread.currentThread().getName() + "]抢票成功" + "目前还剩" + tickets);
} else {
System.out.println("[" + Thread.currentThread().getName() + "]真抱歉!票已经售罄");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
reentrantLock.unlock();
}
}
}