先從代碼說起 , 一個獨佔鎖的實例:
/**
* 獨佔鎖
*/
//Doug lea 的註釋
/*<p>Here is a non-reentrant mutual exclusion lock class that uses
* the value zero to represent the unlocked state, and one to
* represent the locked state. While a non-reentrant lock
* does not strictly require recording of the current owner
* thread, this class does so anyway to make usage easier to monitor.
* It also supports conditions and exposes
* one of the instrumentation methods:*/
public class Mutex implements Lock{
// Our internal helper class
private static class Sync extends AbstractQueuedSynchronizer {
// Report whether in locked state
@Override
protected boolean isHeldExclusively() {
return getState() == 1;
}
// Acquire the lock if state is zero
@Override
protected boolean tryAcquire(int acquires) {
assert acquires == 1; // Otherwise unused
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// Release the lock by setting state to zero
@Override
protected boolean tryRelease(int releases) {
assert releases == 1;// Otherwise unused
if (getState() == 0) throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
// Provide a Condition
Condition newCondition() {
return new ConditionObject();
}
// Deserialize properly
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
// The sync object does all the hard work. We just forward to it.
private final Sync sync = new Sync();
public void lock(){
sync.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock(){
return sync.tryAcquire(1);
}
public Condition newCondition(){
return sync.newCondition();
}
public boolean isLocked(){
return sync.isHeldExclusively();
}
public boolean hasQueuedThreads(){
return sync.hasQueuedThreads();
}
public boolean tryLock(long timeout,TimeUnit timeUnit) throws InterruptedException {
return sync.tryAcquireNanos(1,timeUnit.toNanos(timeout));
}
@Override
public void unlock() {
sync.release(1);
}
}
獨佔鎖指的是同一時刻只能有一個線程獲取到鎖,而其他的線程都處於同步隊列中等待。
上述代碼是java併發包中的AbstractQueuedSynchronizer一段實例代碼
AbstractQueuedSynchronizer
隊列同步器是用來構建鎖或者其他同步組件的基礎框架,它使用了一個int成員變量標示同步狀態,通過內置的fifo隊列來完成資源獲取線程的排隊工作,Doug Lea希望它能夠實現大部分的同步需求的基礎.
同步器是實現鎖的關鍵,簡化了鎖的實現,屏蔽了同步狀態管理,線程的排隊,等待與喚醒等底層操作.
使用
同步器的設計使用了典型的模板方法模式,自定義實現同步器可重寫的方法與描述如下:
同步器可重寫的方法
方法名稱 | 描述 |
---|---|
protected boolean tryAcquire(int arg) | 獨佔式獲取同步狀態,實現該方法需要查詢當前狀態並判斷同步狀態是否符合預期然後進行cas設置同步狀態 |
protected boolean tryRelease(int arg) | 獨佔式釋放同步狀態 等待獲取同步狀態的線程將有機會獲取同步狀態 |
protected int tryAcquireShared(int arg) | 共享式獲取同步狀態,返回大於等於0的值表示獲取成功反之獲取失敗 |
protected boolean tryReleaseShared(int arg) | 共享式釋放同步狀態 |
protected boolean isHeldExclusively() | 當前同步器是否在獨佔模式下被線程佔用,一般該方法表示是否被當前線程所獨佔 |
測試用例
public class MutexTest {
// 一把獨佔鎖
static Lock lock = new Mutex();
static int count = 0;
static ExecutorService executorService = Executors.newFixedThreadPool(10);
static CountDownLatch countDownLatch = new CountDownLatch(10);
public static void main(String[] args) throws InterruptedException {
//
for (int i = 0; i < 10; i++) {
executorService.submit(new MutexRunnable());
}
countDownLatch.await();
System.out.println("count = " + count);
System.exit(0);
//
// Lock lock = new Mutex();
// lock.lock();
// System.out.println("obtain lock");
// lock.unlock();
}
static class MutexRunnable implements Runnable{
@Override
public void run() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
countDownLatch.countDown();
}
}
}
自定義獨佔鎖的測試用例.