Davids原理探究:Java併發包中鎖的原理

Java併發包中鎖的原理

// 獨佔鎖(可重入)
ReentrantLock fairLock = new ReentrantLock();
// 獨佔公平鎖
ReentrantLock fairLock = new ReentrantLock(true);
// 獨佔非公平鎖
ReentrantLock nonFairLock = new ReentrantLock(false);

// 讀寫鎖(可重入)
ReentrantReadWriteLock fairReentrantReadWriteLock = new ReentrantReadWriteLock();
// 公平讀寫鎖
ReentrantReadWriteLock fairReentrantReadWriteLock = new ReentrantReadWriteLock(true);
// 共享讀
ReentrantReadWriteLock.ReadLock readLock = fairReentrantReadWriteLock.readLock();
// 獨佔寫
ReentrantReadWriteLock.WriteLock writeLock = fairReentrantReadWriteLock.writeLock();
// 非公平讀寫鎖
ReentrantReadWriteLock nonFairReentrantReadWriteLock = new ReentrantReadWriteLock(false);
// 共享讀
ReentrantReadWriteLock.ReadLock readLock = nonFairReentrantReadWriteLock.readLock();
// 獨佔寫
ReentrantReadWriteLock.WriteLock writeLock = nonFairReentrantReadWriteLock.writeLock();

// JDK8新增鎖(不可重入)
StampedLock stampedLock = new StampedLock();
// 獨佔寫類似於ReentrantReadWriteLock
long writeStamp = stampedLock.writeLock();
// 悲觀讀,CAS獲取鎖
long readStamp = stampedLock.readLock();
// 樂觀讀,不加鎖(讀時檢查當前是否有寫鎖,沒有則返回非0的stamp,然後讀取所需的值入棧,使用前校驗stampedLock.validate(stamp),期間是否有線程獲取過寫鎖,此過程不加鎖適合讀多寫少的場景,效率高,存在一致性問題,如果校驗過後在操作的時候有線程獲取寫鎖,並修改數據,則當前線程所獲取的副本,會存在不一致,若無法接受,則需使用悲觀鎖。)
long stamp = stampedLock.tryOptimisticRead();

ReentrantLock公平鎖

static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;

    final void lock() {
        acquire(1);
    }

    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
			// !hasQueuedPredecessors()判斷隊列中是否有前置節點,如果有則放棄
            if (!hasQueuedPredecessors() &&
                compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;
            if (nextc < 0)
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
}

ReentrantLock非公平鎖

static final class NonfairSync extends Sync {
   private static final long serialVersionUID = 7316153563782823691L;

   final void lock() {
	// 不判斷是否有前置節點,根據cpu自行分配時間片執行獲取鎖
       if (compareAndSetState(0, 1))
           setExclusiveOwnerThread(Thread.currentThread());
       else
           acquire(1);
   }

   protected final boolean tryAcquire(int acquires) {
       return nonfairTryAcquire(acquires);
   }
}

abstract class AbstractQueuedSynchronizer - hasQueuedPredecessors實現

public final boolean hasQueuedPredecessors() {
    // 正確性取決於head是否在tail之前初始化,以及head.next是否正確(如果當前線程在隊列中)
    Node t = tail; // 以相反的初始化順序讀取字段
    Node h = head;
    Node s;
    return h != t &&
        ((s = h.next) == null || s.thread != Thread.currentThread());
}

ReentrantLock抽象類sync

/** 
 * 此鎖的同步控制基礎。在下面將細分爲公平和非公平版本。使用AQS狀態來表示鎖的保留數。
 */
abstract static class Sync extends AbstractQueuedSynchronizer {
   private static final long serialVersionUID = -5179523762034025860L;

   /**
    * 執行{@link Lock#lock}。子類化的主要原因是爲非公平版本提供了快速路徑。
    */
   abstract void lock();

   /**
    * 執行不公平的tryLock。 tryAcquire是在子類中實現的,但是都需要對trylock方法進行不公平的try。
    */
   final boolean nonfairTryAcquire(int acquires) {
       final Thread current = Thread.currentThread();
       int c = getState();
       if (c == 0) {
           if (compareAndSetState(0, acquires)) {
               setExclusiveOwnerThread(current);
               return true;
           }
       }
       else if (current == getExclusiveOwnerThread()) {
           int nextc = c + acquires;
           if (nextc < 0) // overflow
               throw new Error("Maximum lock count exceeded");
           setState(nextc);
           return true;
       }
       return false;
   }

   protected final boolean tryRelease(int releases) {
       int c = getState() - releases;
       if (Thread.currentThread() != getExclusiveOwnerThread())
           throw new IllegalMonitorStateException();
       boolean free = false;
       if (c == 0) {
           free = true;
           setExclusiveOwnerThread(null);
       }
       setState(c);
       return free;
   }

   protected final boolean isHeldExclusively() {
       // 雖然我們通常必須在擁有者之前先讀取狀態,但無需檢查當前線程是否爲擁有者
       return getExclusiveOwnerThread() == Thread.currentThread();
   }

   final ConditionObject newCondition() {
       return new ConditionObject();
   }

   // 從外部類繼承的方法

   final Thread getOwner() {
       return getState() == 0 ? null : getExclusiveOwnerThread();
   }

   final int getHoldCount() {
       return isHeldExclusively() ? getState() : 0;
   }

   final boolean isLocked() {
       return getState() != 0;
   }

   /**
    * 從流中重構實例(即反序列化它)。
    */
   private void readObject(java.io.ObjectInputStream s)
       throws java.io.IOException, ClassNotFoundException {
       s.defaultReadObject();
       setState(0); // 重置爲解鎖狀態
   }
}

CopyOnWriteArrayList內部由ReentrantLock加鎖實現線程安全

final transient ReentrantLock lock = new ReentrantLock();

/**
 *將指定的元素追加到此列表的末尾。
 *
 * @param e 要添加到此列表的元素
 * @return {@code true} (as specified by {@link Collection#add})
 */
public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        int len = elements.length;
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        newElements[len] = e;
        setArray(newElements);
        return true;
    } finally {
        lock.unlock();
    }
}

/**
 * 用指定的元素替換此列表中指定位置的元素。
 *
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E set(int index, E element) {
	// 獲取鎖
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        E oldValue = get(elements, index);

        if (oldValue != element) {
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len);
            newElements[index] = element;
            setArray(newElements);
        } else {
            // 並非完全禁止操作;確保volatile的寫語義,重刷會主內存
            setArray(elements);
        }
        return oldValue;
    } finally {
		// 釋放鎖
        lock.unlock();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章