Lock接口,和Synchronized區別,分佈式鎖

什麼是鎖:同步的本質是通過鎖來實現的。爲了實現多個線程在一個時刻同一個代碼塊只能有一個線程可執行,那麼需要在某個地方做個標記,這個標記必須每個線程都能看到,當標記不存在時可以設置該標記,其餘後續線程發現已經有標記了則等待擁有標記的線程結束同步代碼塊取消標記後再去嘗試設置標記。這個標記可以理解爲鎖。

Lock接口
(1)Lock接口的實現類有:ReentrantLock,WriteLock,ReadLock,WriteLockView,ReadLockView。
(2)Lock接口中的方法:

  • tryLock():佛係獲取鎖,能獲取就獲取,獲取不到就休眠。
  • tryLock(long,TimeUnit):有時間限制的佛係獲取鎖。

在單進程情況下,多個線程訪問同一資源,可以使用synchronized和lock實現。在多進程情況下,也就是分佈式情況,對同一資源的併發請求,需要使用分佈式鎖實現。下面分別說明一下。

1、單進程情況的鎖,synchronized和lock的區別
(1)synchronized是java的關鍵字,在對象頭設置標記,託管給jvm執行。lock是一個java實現的接口,使用voltile關鍵字修飾的一個變量,保證對所有線程的可見性和原子修改。
(2)因爲第(1)中所說,synchronized對對象頭的標記由jvm執行,獲得鎖和釋放的方式都是在塊結構中,自動釋放鎖。而Lock則需要開發人員手動去釋放,並且必須在finally塊中釋放,否則會引起死鎖問題的發生。

Lock的使用 
psvm 
private static int num = 0;
private static Lock lock = new ReentranLock();
public static void inCreate(){
	lock.lock();
	num++;
	lock.unlock();
}

(3)Lock可以讓等待鎖的線程響應中斷,而synchronized卻不行,使用synchronized時,等待的線程會一直等待下去,不能夠響應中斷;通過Lock可以知道有沒有成功獲取鎖tryLock()和嘗試等待指定時長,而synchronized卻無法辦到。Lock可以提高多個線程進行讀操作的效率。
(4)synchronized鎖的範圍是整個方法或synchronized塊部分;而Lock因爲是方法調用,可以跨方法,靈活性更大。
(5)Lock是樂觀鎖,是CAS機制,每次不加鎖,遇到重入失敗就重試,直到成功爲止;Synchronized是悲觀鎖,線程獲取的是獨佔鎖,其他線程只能被阻塞,等待線程釋放鎖。(悲觀鎖、樂觀鎖的區別及使用場景
(6)Lock的使用和Synchronized的效果是一樣的。
(7)JDK1.5之前,Synchronized性能不好,現在的版本JDK1.6,好多了,和Lock的性能差不多了。

ReentrantLock的使用

2、分佈式鎖
主要實現方式:基於數據庫、redis、zk實現。
Java分佈式鎖看這篇就夠了

基於redis實現的分佈式鎖:

public class RedisLock {
    @Autowired
	private RedisService redisService;
    public boolean tryLock(String lockKey, String value, long expireTime) {
        if (!StringUtil.isBlank(lockKey) && !StringUtil.isBlank(value) && expireTime > 0L) {
            try {
                boolean successFlag = this.redisService.setNX(lockKey, value);
                if (successFlag) {
                    boolean expireFlag = this.redisService.expire(lockKey, expireTime, TimeUnit.SECONDS);
                    return true;
                } else {
                    return false;
                }
            } catch (RuntimeException var7) {
                LOG.error("RedisLock-->tryLock error", var7);
                return false;
            }
        } else {
            LOG.error("RedisLock-->tryLock invalid parameter");
            return false;
        }
    }

    public void unLock(String lockKey) {
        if (StringUtil.isBlank(lockKey)) {
            LOG.error("RedisLock-->unLock invalid parameter");
        } else {
            try {
                this.redisService.del(lockKey);
                if (!this.redisService.exists(lockKey)) {
                    LOG.debug("RedisLock-->unLock release lock success lockKey:{}", lockKey);
                } else {
                    LOG.error("RedisLock-->unLock release lock error lockKey:{}", lockKey);
                }
            } catch (RuntimeException var3) {
                LOG.error("RedisLock-->unLock execute error ", var3);
            }
        }
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章