电商平台中最重要的一点就是卖东西。同个商品不能无限制的卖下去的,因为商品有库存量,超过库存就不能卖了。
这里,约定一个规则,下单使库存减n,取消订单使库存加m。库存数量不可以小于0。
假设平台上同时有很多用户在操作,在不考虑效率的情况下,我们用同步方法来模拟这个场景。
首先写一个订单处理类:
class OrderHandler{
/*初始某商品库存量*/
int StockSomeGoodsNum=200;
/*用户下单*/
public void Produce(int n){
/*step1:判断可用库存操作*/
if((StockSomeGoodsNum-n)>=0){
/*为了更好体现线程间的竞争,让进程休眠一下*/
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
/*step2:执行减少库存操作*/
StockSomeGoodsNum-=n;
System.out.println("用户" + Thread.currentThread().getName()
+ "成功购买商品:" + String.valueOf(n)+"个,库存剩余"+StockSomeGoodsNum+"个");
}else{
System.out.println("用户" + Thread.currentThread().getName()
+ "下单失败,库存不足" + String.valueOf(n)+"个,库存剩余"+StockSomeGoodsNum+"个");
}
}
/*用户取消订单*/
public void Cancel(int n){
StockSomeGoodsNum+=n;
System.out.println("用户" + Thread.currentThread().getName()
+ "取消购买商品:" + String.valueOf(n)+"个,库存剩余"+StockSomeGoodsNum+"个");
}
}
可以看到类中的两个方法都会操作StockSomeGoodsNum
变量
在用户下单方法void Produce(int n)中,首先判断库存数量够不够,如果够了对库存数量进行减少操作。这里涉及两个步骤:判断库存、减少库存。这两个步骤组成一个事务,是不允许分开和打乱的。但现在是多个线程并发执行,就有可能在这两个步骤之间,有别的线程执行了增减库存操作。
现在在主函数中开启多个线程来模拟用户下单和取消订单的操作:
public static void main(String[] args) {
final OrderHandler orderHandler=new OrderHandler();
/*开启10个线程,模拟10个用户进行下单操作*/
for(int i=0;i<10;i++){
new Thread(new Runnable() {
public void run() {
/*每个人购买商品数量为25个*/
orderHandler.Produce(25);
}
}).start();
}
/*开启5个线程,模拟5个用户在进行取消订单操作*/
for(int i=0;i<5;i++){
new Thread(new Runnable() {
public void run() {
/*每个取消订单中包含的商品数为3个*/
orderHandler.Cancel(3);
}
}).start();
}
}
}
运行结果:
用户Thread-10取消购买商品:3个,库存剩余203个
用户Thread-12取消购买商品:3个,库存剩余209个
用户Thread-11取消购买商品:3个,库存剩余206个
用户Thread-13取消购买商品:3个,库存剩余212个
用户Thread-14取消购买商品:3个,库存剩余215个
用户Thread-1成功购买商品:25个,库存剩余165个
用户Thread-2成功购买商品:25个,库存剩余140个
用户Thread-0成功购买商品:25个,库存剩余165个
用户Thread-3成功购买商品:25个,库存剩余115个
用户Thread-4成功购买商品:25个,库存剩余65个
用户Thread-5成功购买商品:25个,库存剩余65个
用户Thread-8成功购买商品:25个,库存剩余-10个
用户Thread-6成功购买商品:25个,库存剩余15个
用户Thread-7成功购买商品:25个,库存剩余-10个
用户Thread-9成功购买商品:25个,库存剩余-35个
出现了负数,说明在判断库存、减少库存的两个步骤中有其它线程执行,导致结果不正确。现在我们在Produce()和Cancle()方法前加上synchronized关键字,让它们成为同步方法。
再次运行结果:
用户Thread-0成功购买商品:25个,库存剩余175个
用户Thread-14取消购买商品:3个,库存剩余178个
用户Thread-13取消购买商品:3个,库存剩余181个
用户Thread-12取消购买商品:3个,库存剩余184个
用户Thread-11取消购买商品:3个,库存剩余187个
用户Thread-10取消购买商品:3个,库存剩余190个
用户Thread-9成功购买商品:25个,库存剩余165个
用户Thread-8成功购买商品:25个,库存剩余140个
用户Thread-7成功购买商品:25个,库存剩余115个
用户Thread-6成功购买商品:25个,库存剩余90个
用户Thread-5成功购买商品:25个,库存剩余65个
用户Thread-4成功购买商品:25个,库存剩余40个
用户Thread-3成功购买商品:25个,库存剩余15个
用户Thread-2下单失败,库存不足25个,库存剩余15个
用户Thread-1下单失败,库存不足25个,库存剩余15个
结论:
各个线程间能保持如此好的协作,其关键原因就是OrderHandler类中的方法都是synchronized同步方法,因此他们有共同的锁:this,当一个线程运行时,其它线程都被阻塞,这样保证了程序的正常运行。
synchronized同步方法虽然很安全,但效率也很低。synchronized同步方法是串行运行的,多个线程排队,并没有并发执行。因此在实际业务开发中要注意。