Lock是一個接口提供無條件的,可輪詢的 ,定時的,可中斷的鎖獲取操作,所有加鎖和解鎖的方法都是顯示的。
Lock接口方法
public abstract void lock(); //獲取鎖
這個就是平常用的最多的方法,用來獲取鎖,如果沒有獲取到鎖則等待。不過為了避免產生死鎖,一般都要跟try{}finally{} 一起使用
lock.lock(); //獲取鎖
try {
//業務處理
}finally {
lock.unlock(); //釋放鎖
}
}
public abstract void unlock(); //釋放鎖
用來釋放鎖,這個沒什么好細說,用的時候,注意一定在finally包裹里使用,不然容易出現死鎖。
public abstract void lockInterruptibly()throws InterruptedException; //獲取鎖
這個方法是也是獲取鎖,跟lock() 跟相似,獲取鎖,獲取不到,等待直到獲取到鎖為止。但是它是可以被中斷的,這個方法直接throws InterruptedException 就是為了讓調用者,自己去處理線程的中斷。這個方法強調的是線程在獲取鎖的時候可以被中斷,獲取到鎖的時候也可以被中斷,詳細看下面的例子。
void method()throws InterruptedException{
try {
//業務處理
}finally {
lock.unlock(); //釋放鎖
}
}
public abstract boolean tryLock(); //獲取鎖,有返回值
這個方法與lock()主要的區別在,lock()方法獲取不到鎖,會等待,直到獲取到鎖為止。tryLock()只會獲取一次,并將結果返回,獲取到鎖返回true,反之false。代碼模板:
if(lock.tryLock()) {
try {
//上鎖的業務處理
}finally {
lock.unlock(); //釋放鎖
}
}else {
//獲取鎖失敗的業務處理
}
public void tryLock(long paramLong,TimeUnit paramTimeUnit) throws InterruptedException;
這個方法與tryLock()有點類似,在指定的時間內獲取鎖,如果沒有獲取到返回false,如果在指定的時間內,獲取到鎖則返回true。使用模板也與tryLock() 一樣。
public abstract Condition newCondition();
返回用來與此Lock實例一起使用的Condition實例。
Lock實現ReentrantLock 使用
lock() 方法使用
public class LockDemo {
private List<String> list = new ArrayList<>();
private final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
final LockDemo l = new LockDemo();
for(int i = 0; i < 5 ; i++) {
new Thread(()->{l.insert(Thread.currentThread());}).start();
}
Thread.sleep(2000); //為了看到list的結果,誰兩秒鐘
System.out.println("執行完成了");
l.list.forEach(System.out::println);
}
public void insert(Thread thread) {
lock.lock();
try {
System.out.println("此線程已經獲取到鎖了 "+thread.getName());
list.add(thread.getName());
}finally {
lock.unlock();
System.out.println("此線程已經釋放鎖了 "+thread.getName());
}
}
}
}
執行結果
此線程已經獲取到鎖了 Thread-1
此線程已經釋放鎖了 Thread-1
此線程已經獲取到鎖了 Thread-0
此線程已經釋放鎖了 Thread-0
此線程已經獲取到鎖了 Thread-3
此線程已經釋放鎖了 Thread-3
此線程已經獲取到鎖了 Thread-4
此線程已經釋放鎖了 Thread-4
此線程已經獲取到鎖了 Thread-2
此線程已經釋放鎖了 Thread-2
執行完成了
Thread-1
Thread-0
Thread-3
Thread-4
Thread-2
可以看出獲取鎖的順序跟list的順序是一樣。每個線程都是先獲取到鎖,釋放鎖在到下一個線程,不存在交叉的情況。
tryLock() 方法使用
public class LockDemo {
private List<String> list = new ArrayList<>();
private final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
final LockDemo l = new LockDemo();
for(int i = 0; i < 5 ; i++) {
new Thread(()->{l.tryInsert(Thread.currentThread());}).start();
}
Thread.sleep(2000);
System.out.println("執行完成了");
l.list.forEach(System.out::println);
}
void tryInsert(Thread thread) {
if(lock.tryLock()) {//tryLock()方法是有返回值的,它表示用來嘗試獲取鎖,如果獲取成功,則返回true,如果獲取失敗(
System.out.println("此線程已經獲取到鎖了 "+thread.getName()); //即鎖已被其他線程獲取),
try { //則返回false,也就說這個方法無論如何都會立即返回。在拿不到鎖時不會一直在那等待。 這個方法就是線程 去競爭鎖,獲取到執行 不然到else里面去
list.add(thread.getName());
}finally {
lock.unlock();
System.out.println("此線程已經釋放鎖了 "+thread.getName());
}
}else {
System.out.println("此線程獲取鎖失敗 "+thread.getName());
}
}
}
執行的結果
此線程獲取鎖失敗 Thread-0
此線程獲取鎖失敗 Thread-3
此線程獲取鎖失敗 Thread-1
此線程獲取鎖失敗 Thread-2
此線程已經獲取到鎖了 Thread-4
此線程已經釋放鎖了 Thread-4
執行完成了
Thread-4
可以看出5個線程同時獲取鎖,只有一個線程成功的,其他的線程都進入else中。這個對應開頭說的可輪詢的,如果加上時間就是定時的。
lockInterruptibly()方法使用
public class LockDemo {
private List<String> list = new ArrayList<>();
private final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
final LockDemo l = new LockDemo();
for (int i = 0; i < 5; i++) {
Thread t = new Thread(() -> {
l.interruptInsert(Thread.currentThread());
});
t.start();
if (i % 2 == 0) {//對偶數進行中斷,為了不讓全部的線程都中斷,list沒有結果集
Thread.sleep(10); //讓線程獲取去獲取鎖,在進行中斷
t.interrupt(); // 直接執行中斷
}
}
Thread.sleep(5000);
System.out.println("執行完成了");
l.list.forEach(System.out::println);
}
void interruptInsert(Thread thread) {
try {
lock.lockInterruptibly();
System.out.println("線程已經獲取到鎖了 : " + thread.getName());
Thread.sleep(2000);
list.add(thread.getName());
} catch (InterruptedException e) {
System.out.println("當前線程直接執行中斷: " + thread.getName());
e.printStackTrace();
} finally {
lock.unlock(); // 釋放鎖
System.out.println("此線程已經釋放鎖了 " + thread.getName());
}
}
}

可以看出Thread-0,Thread-2 已經獲取到鎖了,還是被中斷,Thread-4在等待獲取鎖,直接被中斷的,終止等待。