什麼是可重入鎖?它有什麼作用?
可重入鎖,也叫做遞歸鎖,指的是在同一線程內,外層函數獲得鎖之後,內層遞歸函數仍然可以獲取到該鎖。
說白了就是同一個線程再次進入同樣代碼時,可以再次拿到該鎖。
它的作用是:防止在同一線程中多次獲取鎖而導致死鎖發生。
在java的編程中synchronized 和 ReentrantLock都是可重入鎖。
案例實戰:基於synchronized下訂單的可重入鎖
業務場景:模仿下訂單操作,先減庫存,再插入訂單表。
步驟1:庫存加鎖,訂單也加鎖
public class SynchronizedDemo {
//模擬庫存100
int count=100;
public synchronized void operation(){
log.info("第一層鎖:減庫存");
//模擬減庫存
count--;
add();
log.info("下訂單結束庫存剩餘:{}",count);
}
private synchronized void add(){
log.info("第二層鎖:插入訂單");
try {
Thread.sleep(1000*10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
步驟2:加個測試類
public class SynchronizedController {
SynchronizedDemo synchronizedDemo=new SynchronizedDemo();
@GetMapping(value = "/lock1")
public void lock1(String key) {
log.info("-------用戶{}開始下單--------",key);
this.synchronizedDemo.operation();
}
}
步驟3:測試體驗
2020-03-08 10:47:52.038 INFO 75593 --- [nio-9090-exec-9] c.a.r.controller.SynchronizedController : -------用戶1開始下單--------
2020-03-08 10:47:52.039 INFO 75593 --- [nio-9090-exec-9] c.agan.redis.Reentrant.SynchronizedDemo : 第一層鎖:減庫存
2020-03-08 10:47:52.039 INFO 75593 --- [nio-9090-exec-9] c.agan.redis.Reentrant.SynchronizedDemo : 第二層鎖:插入訂單
2020-03-08 10:47:54.606 INFO 75593 --- [io-9090-exec-10] c.a.r.controller.SynchronizedController : -------用戶2開始下單--------
2020-03-08 10:47:56.613 INFO 75593 --- [nio-9090-exec-1] c.a.r.controller.SynchronizedController : -------用戶3開始下單--------
2020-03-08 10:48:02.047 INFO 75593 --- [nio-9090-exec-9] c.agan.redis.Reentrant.SynchronizedDemo : 下訂單結束庫存剩餘:99
2020-03-08 10:48:02.047 INFO 75593 --- [nio-9090-exec-1] c.agan.redis.Reentrant.SynchronizedDemo : 第一層鎖:減庫存
2020-03-08 10:48:02.047 INFO 75593 --- [nio-9090-exec-1] c.agan.redis.Reentrant.SynchronizedDemo : 第二層鎖:插入訂單
2020-03-08 10:48:12.057 INFO 75593 --- [nio-9090-exec-1] c.agan.redis.Reentrant.SynchronizedDemo : 下訂單結束庫存剩餘:98
2020-03-08 10:48:12.057 INFO 75593 --- [io-9090-exec-10] c.agan.redis.Reentrant.SynchronizedDemo : 第一層鎖:減庫存
2020-03-08 10:48:12.057 INFO 75593 --- [io-9090-exec-10] c.agan.redis.Reentrant.SynchronizedDemo : 第二層鎖:插入訂單
2020-03-08 10:48:22.064 INFO 75593 --- [io-9090-exec-10] c.agan.redis.Reentrant.SynchronizedDemo : 下訂單結束庫存剩餘:97
通過測試結果:
1.發送了3次請求,springboot啓用了3條線程來處理,分別是nio-9090-exec-9 io-9090-exec-10 nio-9090-exec-1
2.nio-9090-exec-9線程,在operation()方法內能正常調用add(),即證明了Synchronized是可重入鎖
3.只有當nio-9090-exec-9線程執行完後,才能執行io-9090-exec-10 nio-9090-exec-1,爲什麼?
因爲線程之間的請求都被鎖住了,也證明了Synchronized在不同的線程之間是不可重入的。