先从代码说起 , 一个独占锁的实例:
/**
* 独占锁
*/
//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();
}
}
}
自定义独占锁的测试用例.