公平鎖和非公平鎖的區別
- 公平鎖 指在分配鎖前檢查是否有線程在排隊等待獲取該鎖,優先將鎖分配給排隊時間最長的線程
- 非公平鎖 指在分配鎖時不考慮線程排隊等待的情況,直接嘗試獲取鎖,在獲取不到鎖時再排到隊尾等待
因爲公平鎖需要在多核的情況下維護一個鎖線程等待隊列,基於該隊列進行鎖的分配,因此效率比非公平鎖低很多,java中的synchronized時非公平鎖,ReentranLock默認的lock方法採用的時非公平鎖。
讀寫鎖:ReadWriteLock
- 在Java中通過Lock接口及對象可以方便的爲對象加鎖和釋放鎖,但是這種鎖不區分讀寫,叫做普通鎖。爲了提供性能,Java提供了讀寫鎖,讀寫鎖分爲讀鎖和寫鎖,在寫的地方使用寫鎖,在沒有寫的地方,讀時無阻塞的。
- 如果系統要求共享數據可以同事支持很多線程併發讀,但不能支持很多線程併發寫,那麼使用讀鎖能很大程度地提高效率,如果系統要求共享數據在同一時刻只能有一個線程在寫,再寫的過程中不能讀取共享數據,則需要使用寫鎖。
public class SeafCache{
private final Map<String,Object> cache= new HashMap<String,Object>();
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock =rwlock.readLock();
private final Lock writeLock =rwlock.writeLock();
public Object get(String key){
readLock.lock();
try{
return cache.get(key);
}finally{
readLock.unLock();
}
}
public Object put(String key,Object value){
writeLock.lock();
try{
return cache.put(key,value);
}finally{
writeLock.lock();
}
}
}
共享鎖和獨佔鎖
- 獨佔鎖:也叫互斥鎖,每次只允許一個線程持有該鎖,ReentrantLock爲獨佔鎖的實現
- 共享鎖:允許多個線程同時獲取該鎖,併發訪問共享資源。ReentrantReadWriteLock中的讀鎖爲共享鎖的實現。
ReentrantReadWriteLock的加鎖和解鎖操作最終都調用內部類Sync提供的方法。Sync對象通過繼承AQS(Abstract Queued Synchronizer)進行實現。AQS的內部類Node定義了兩個常量SHARED和EXCLUSIVE,費別標識AQS隊列中等待線程的鎖獲取模式。
獨佔鎖是一種悲觀的枷鎖策略,同一時刻只允許一個讀線程讀取鎖資源,限制了讀操作的併發性;因爲併發讀線程並不會影像數據的一致性,因此共享鎖採用了樂觀的枷鎖策略,允許多個執行讀操作的線程同時訪問共享資源。