【多線程】可重入鎖 ReentrantLock
java除了使用關鍵字synchronized外,還可以使用ReentrantLock實現獨占鎖的功能。而且ReentrantLock相比synchronized而言功能更加豐富,使用起來更為靈活,也更適合復雜的并發場景。
一、簡介
ReentrantLock常常對比著synchronized來分析,我們先對比著來看然后再一點一點分析。
- synchronized是獨占鎖,加鎖和解鎖的過程自動進行,易于操作,但不夠靈活。ReentrantLock也是獨占鎖,加鎖和解鎖的過程需要手動進行,不易操作,但非常靈活。
- synchronized可重入,因為加鎖和解鎖自動進行,不必擔心最后是否釋放鎖;ReentrantLock也可重入,但加鎖和解鎖需要手動進行,且次數需一樣,否則其他線程無法獲得鎖。
- synchronized不可響應中斷,一個線程獲取不到鎖就一直等著;ReentrantLock可以響應中斷。
ReentrantLock好像比synchronized關鍵字沒好太多,我們再去看看synchronized所沒有的,一個最主要的就是ReentrantLock還可以實現公平鎖機制。什么叫公平鎖呢?也就是在鎖上等待時間最長的線程將獲得鎖的使用權。通俗的理解就是誰排隊時間最長誰先執行獲取鎖。
二、使用
1、簡單使用
代碼:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @description 可重入鎖測試
* @author hzx
* @date 2022-04-01
*/
public class ReentrantLockTest {
private static final Lock lock = new ReentrantLock();
public static void main(String[] args) {
new Thread(() -> test(),"線程A").start();
new Thread(() -> test(),"線程B").start();
}
public static void test() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"獲取了鎖");
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName()+"釋放了鎖");
lock.unlock();
}
}
}
執行結果:
線程A獲取了鎖
線程A釋放了鎖
線程B獲取了鎖
線程B釋放了鎖
在這里我們定義了一個ReentrantLock,然后再test方法中分別lock和unlock,運行一邊就可以實現我們的功能。這就是最簡單的功能實現,代碼很簡單。我們再看看ReentrantLock和synchronized不一樣的地方,那就是公平鎖的實現。
2、公平鎖實現
首先new一個ReentrantLock的時候參數為true,表明實現公平鎖機制。公平鎖的含義就是誰等的時間最長,誰就先獲取鎖。在這里我們多定義幾個線程,然后在test方法中循環執行了兩次加鎖和解鎖的過程。
代碼:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @description 可重入鎖測試(公平鎖實現)
* @author hzx
* @date 2022-04-01
*/
public class ReentrantLockTest2 {
private static final Lock lock = new ReentrantLock(true);
public static void main(String[] args) {
new Thread(() -> test(),"線程1").start();
new Thread(() -> test(),"線程2").start();
new Thread(() -> test(),"線程3").start();
new Thread(() -> test(),"線程4").start();
new Thread(() -> test(),"線程5").start();
}
public static void test() {
for (int i = 0; i < 2; i++) {
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"獲取了鎖");
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
執行結果:
線程1獲取了鎖
線程2獲取了鎖
線程3獲取了鎖
線程4獲取了鎖
線程5獲取了鎖
線程1獲取了鎖
線程2獲取了鎖
線程3獲取了鎖
線程4獲取了鎖
線程5獲取了鎖
3、非公平鎖實現
非公平鎖那就隨機的獲取,誰運氣好,cpu時間片輪到哪個線程,哪個線程就能獲取鎖,和上面公平鎖的區別很簡單,就在于先new一個ReentrantLock的時候參數為false,當然我們也可以不寫,默認就是false。
代碼:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @description 可重入鎖測試(非公平鎖實現)
* @author hzx
* @date 2022-04-01
*/
public class ReentrantLockTest3 {
private static final Lock lock = new ReentrantLock(false);
public static void main(String[] args) {
new Thread(() -> test(),"線程1").start();
new Thread(() -> test(),"線程2").start();
new Thread(() -> test(),"線程3").start();
new Thread(() -> test(),"線程4").start();
new Thread(() -> test(),"線程5").start();
}
public static void test() {
for (int i = 0; i < 2; i++) {
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"獲取了鎖");
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
執行結果:
線程1獲取了鎖
線程2獲取了鎖
線程2獲取了鎖
線程3獲取了鎖
線程1獲取了鎖
線程3獲取了鎖
線程4獲取了鎖
線程4獲取了鎖
線程5獲取了鎖
線程5獲取了鎖
整個過程是隨機的,沒有固定的先后順序,親自測試時可以將for循環的次數增大,可以明顯看出效果。

浙公網安備 33010602011771號