不用锁
JavaLock.java
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.ReentrantLock;
@Slf4j
public class JavaLock {
/**
* 库存
*/
private static Integer productCount = 5000;
/**
* 可重入锁
*/
private static final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
new Thread(new JavaLockRunnable(),"第1个线程").start();
new Thread(new JavaLockRunnable(),"第2个线程").start();
new Thread(new JavaLockRunnable(),"第3个线程").start();
new Thread(new JavaLockRunnable(),"第4个线程").start();
new Thread(new JavaLockRunnable(),"第5个线程").start();
}
/**
* 不推荐,不使用锁,线程不安全会导致库存数量有问题!
*/
public static void reduceCount(){
log.info("当前数量:{}",productCount--);
}
/**
* 推荐,使用synchronized锁住调用方法可以解决并发问题,性能较低
*/
public synchronized static void synchronizedReduceCount(){
log.info("当前数量:{}",productCount--);
}
/**
* 推荐,使用ReentrantLock锁住代码块也可以解决并发问题,性能较高
*/
public static void reentrantLockReduceCount(){
//加锁
lock.lock();
try {
log.info("当前数量:{}",productCount--);
}catch (Exception e){
throw new RuntimeException(e);
}finally {
//必须在finally里解锁,防止死锁。
lock.unlock();
}
}
}
JavaLockRunnable.java
public class JavaLockRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
JavaLock.reduceCount();
// JavaLock.synchronizedReduceCount();
// JavaLock.reentrantLockReduceCount();
}
}
}
运行输出:(数量紊乱)
20:33:15.780 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:5000
20:33:15.787 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4995
20:33:15.787 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4994
20:33:15.787 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4993
20:33:15.787 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4992
20:33:15.787 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4991
20:33:15.787 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4990
20:33:15.787 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4989
20:33:15.787 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4988
20:33:15.781 [第3个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4997
20:33:15.787 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4987
修改JavaLockRunnable使用synchronized锁住调用方法
public class JavaLockRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
// JavaLock.reduceCount();
JavaLock.synchronizedReduceCount();
// JavaLock.reentrantLockReduceCount();
}
}
}
运行输出:(结果正常)
20:39:14.094 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:5000
20:39:14.098 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4999
20:39:14.099 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4998
20:39:14.099 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4997
20:39:14.099 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4996
20:39:14.099 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4995
20:39:14.099 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4994
20:39:14.099 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4993
20:39:14.099 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4992
20:39:14.099 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4991
20:39:14.099 [第1个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4990
修改JavaLockRunnable使用ReentrantLock锁住方法块
public class JavaLockRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
// JavaLock.reduceCount();
// JavaLock.synchronizedReduceCount();
JavaLock.reentrantLockReduceCount();
}
}
}
运行输出:(结果正常)
20:40:46.087 [第2个线程] INFO com.fu.demo.base.JavaLock - 当前数量:5000
20:40:46.093 [第2个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4999
20:40:46.093 [第2个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4998
20:40:46.094 [第2个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4997
20:40:46.094 [第2个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4996
20:40:46.094 [第2个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4995
20:40:46.094 [第2个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4994
20:40:46.094 [第2个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4993
20:40:46.094 [第2个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4992
20:40:46.094 [第2个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4991
20:40:46.094 [第2个线程] INFO com.fu.demo.base.JavaLock - 当前数量:4990
失效场景
- 多实例(例如:有多个库存)
- 事务(例如:Read UnCommitted读未提交)
- 集群(例如:利用nginx负载均衡跑N个集群。因为我们这里只是模拟线程,所以跑集群也不会有什么问题,要真实模拟就要借助第三方工具)