前言
重入鎖(ReentrantLock)是一種遞歸無阻塞的同步機制。
重入鎖,也叫做遞歸鎖,指的是同一線程 外層函數獲得鎖之后 ,內層遞歸函數仍然有獲取該鎖的代碼,但不受影響。
在JAVA環境下 ReentrantLock 和synchronized 都是 可重入鎖
舉個例子-重入鎖
從例子可以看出,如果同一個線程調用了兩次lock方法,第一次lock時候鎖定計數為1,第二次調用發現已經被鎖定了,直接就返回1.
這就是重入鎖,如果是自旋鎖就不是這樣,請看下面的例子
public class Test implements Runnable {
public synchronized void get() {
System.out.println(Thread.currentThread().getId());
set();
}
public synchronized void set() {
System.out.println(Thread.currentThread().getId());
}
@Override
public void run() {
get();
}
public static void main(String[] args) {
Test ss = new Test();
new Thread(ss).start();
new Thread(ss).start();
new Thread(ss).start();
}
class Test implements Runnable {
ReentrantLock lock = new ReentrantLock();
public void get() {
lock.lock();
System.out.println(Thread.currentThread().getId());
set();
lock.unlock();
}
public void set() {
lock.lock();
System.out.println(Thread.currentThread().getId());
lock.unlock();
}
@Override
public void run() {
get();
}
public static void main(String[] args) {
Test ss = new Test();
new Thread(ss).start();
new Thread(ss).start();
new Thread(ss).start();
}
}
}
自旋鎖
由于自旋鎖使用者一般保持鎖時間非常短,因此選擇自旋而不是睡眠是非常必要的,自旋鎖的效率遠高于互斥鎖。
如何旋轉呢?何為自旋鎖,就是如果發現鎖定了,不是睡眠等待,而是采用讓當前線程不停地的在循環體內執行實現的,當循環的條件被其他線程改變時 才能進入臨界區
代碼演示如何自選
/**
* @Package: com.example.lock
* @Description: 自旋鎖
* @author: liuxin
* @date: 2017/8/28 下午4:48
*/
public class SpinLock {
//初始化為當前線程
private AtomicReference<Thread> sign = new AtomicReference<>();
public void lock() {
Thread current = Thread.currentThread();
//null 不等于當前線程,返回false !fasle=true進入自選
while (!sign.compareAndSet(null, current)) {
}
}
public void unlock() {
Thread current = Thread.currentThread();
//對比current= 初始化信息,所以為true,并設置為null,此時
// while (!sign.compareAndSet(null, current)),所以,null=null,lock中自旋結束,當一個鎖完成,sign中有回到初始化狀態。
sign.compareAndSet(current, null);
}
}
使用了CAS原子操作,lock函數將owner設置為當前線程,并且預測原來的值為空。unlock函數將owner設置為null,并且預測值為當前線程。
當有第二個線程調用lock操作時由于owner值不為空,導致循環一直被執行,直至第一個線程調用unlock函數將owner設置為null,第二個線程才能進入臨界區。
由于自旋鎖只是將當前線程不停地執行循環體,不進行線程狀態的改變,所以響應速度更快。但當線程數不停增加時,性能下降明顯,因為每個線程都需要執行,占用CPU時間。如果線程競爭不激烈,并且保持鎖的時間段。適合使用自旋鎖。