併發包下Lock是如何解決原子性問題的
除了synchronized能解決原子性性問題,Jdk1.5以後,在java.util.concurrent.locks.Lock包下的Lock也能解決原子性問題。
java.util.concurrent.locks.Lock下有一組實現執行緒同步的介面和類。
Lock是介面,使用時我們是使用的他的實現類。Lock的實現類有很多,我們常使用的是ReentrantLock。
PS:使用IDEA的同學,在選中介面類的情況下,可以使用快捷鍵【Ctrl+Alt+B】來檢視介面的實現類。
比如檢視Lock的實現類:
我們來看下Lock介面的原始碼:
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
複製程式碼
方法解釋:
-
void lock() 用來獲取鎖,如果鎖已經被其他執行緒獲取,則一直等待,直到獲取到鎖
-
void lockInterruptibly() throws InterruptedException; 該方法獲取鎖時,可以響應中斷,比如現在有兩個執行緒,一個已經獲取到了鎖,另一個執行緒呼叫這個方法正在等待鎖,但是此刻又不想讓這個執行緒一直在這死等,可以通過呼叫執行緒的Thread.interrupted()方法,來中斷執行緒的等待過程
-
boolean tryLock(); tryLock方法會返回bool值,該方法會嘗試著獲取鎖,如果獲取到鎖,就返回true,如果沒有獲取到鎖,就返回false,但是該方法會立刻返回,而不會一直等待
-
boolean tryLock(long time, TimeUnit unit) throws InterruptedException; 這個方法和上面的tryLock差不多是一樣的,只是會嘗試指定的時間,如果在指定的時間內拿到了鎖,則會返回true,如果在指定的時間內沒有拿到鎖,則會返回false
-
void unlock(); 釋放鎖
-
Condition newCondition(); 實現執行緒通訊,相當於wait和notify,後面會單獨講解
使用Lock是需要手動釋放鎖的,但是如果程式中丟擲了異常,那麼就無法做到釋放鎖,有可能引起死鎖,
所以我們在使用Lock的時候,有一種固定的格式,如下:
Lock lock = new ReentrantLock();
l.lock();
try {
// 業務程式碼
............
} finally {
l.unlock();
}
複製程式碼
下面我就把i++的例子改成使用Lock來解決原子性。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class AddILock {
public static volatile int i = 0;
static Lock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> add(1000000));
Thread t2 = new Thread(() -> add(1000000));
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
public static void add(int n) {
lock.lock();
try {
for (int m = 0; m < n; m++) {
i++;
}
} finally {
lock.unlock();
}
}
}
複製程式碼
執行結果:
2000000
複製程式碼
ReentrantLock實現了公平鎖和非公平鎖兩種方式。公平鎖和非公平鎖請看這篇:
公平鎖和非公平鎖-ReentrantLock是如何實現公平、非公平的
ReentrantLock是可重入鎖。通過命名我們就能看出來reentrant。可重入鎖請看這篇:
可重入鎖-synchronized是可重入鎖嗎?ReentrantLock如何實現可重入的?
小技巧:IDEA的快捷鍵【Ctrl+Alt+U】可以快速檢視類的層次結構圖。
比如檢視非公平鎖NonfairSync的類圖: