首先,concurrent类库在java中应该算是非常重要的类库了,在构建一些同步代码,容器,并发什么的都可以在这个类库中找到现成的可以用...
而在这个类库中最最核心的一个类型就是AbstractQueuedSynchronizer类型,可以基于它来实现自己的同步工具,例如ReentrantLock类型其实就是基于它来实现的...
而且在前面tomcat的源码中,它自己定义的LimitLatch也是基于AbstractQueuedSynchronizer实现的...而且AbstractQueuedSynchronizer这一套工具类的代码就是Doug Lea大神...
当然可能自己现在还没有精力去深入的理解大神代码的精神吧。。就先看看怎么用就好了。。
嗯,先来说AbstractQueuedSynchronizer是干啥用的。。。
(1)用于实现同步组件,例如锁什么的。
(2)通过获取以及释放操作,实现线程的阻塞,同时它内部还维护一个FIFO队列,用于维护阻塞的线程。。
这里获取和释放分为了两种类型,一种是独占的,一种是共享的,这里通过这两个名字应该能明白是什么意思吧。。。
这里就先来看看独占的方式怎么用吧,我们用它来实现一个可重入的独占锁。。。
public class ExLock { private class Sync extends AbstractQueuedSynchronizer { public Sync() { super(); } protected boolean tryAcquire(int arg) { int state = this.getState(); //获取当前的状态 if (state == 0 && this.compareAndSetState(0, 1)) { // 如果是0,而且可以原子的更新为1,那么表示可以上锁了 this.setExclusiveOwnerThread(Thread.currentThread()); //表示当前被这个线程独占的持有了 return true; //返回true,表示可以上锁 } if (this.getExclusiveOwnerThread() == Thread.currentThread()) { //如果当前线程已经持有锁了,那么更新计数就好了 this.setState(state + 1); //将计数加1 return true; //返回true,表示可以上锁 } return false; //返回false,表示上锁失败,这样线程将会被阻塞,同时被放到队列 } protected boolean tryRelease(int arg) { if (this.getExclusiveOwnerThread() == Thread.currentThread()) { //当前线程就是持有锁的线程 int state = this.getState(); //获取当前的计数 int next = state - 1; //减一,表示这次释放之后的计数 this.setState(next); //更新计数 if (next == 0) { //如果已经变成0了,那么表示整个锁已经释放了 this.setExclusiveOwnerThread(null); //那么持有锁为null return true; //返回true,表示整个锁已经释放,那么将会唤醒等待队列上的线程 } else { return false; //表示还有释放完 } } else { //只有持有锁的线程才能释放锁呀 return false; } } } private Sync sync = new Sync(); public void lock() throws InterruptedException { this.sync.acquireInterruptibly(1); //待会会调用tryAcquire来判断是否可以上锁,这里可以接受Interrupt } public void unLock() { this.sync.release(1); //待会会调用tryRelease来判断是否可以释放 } public static void main(String args[]) throws InterruptedException { ExLock lock = new ExLock(); lock.lock(); lock.unLock(); System.out.println("aaaaa"); } }
没有几行代码吧,就实现了一个可以重入的独占锁,这里内部类Sync通过继承AbstractQueuedSynchronizer类型来工作。。
这里因为是独占的,所以获取以及释放对应的方法是:
acquire()或者acquireInterruptibly(),这里区别在于是否能够响应interrupt,然后释放是release()方法。。。
对于acquire和acquireInterruptibly方法,在AbstractQueuedSynchronizer中将会调用tryAcquire方法来判断当前是否能够上锁,如果可以的话,那么返回ture,如果不行的话,那么返回false,如果返回false,那么当前线程将会被阻塞,同时被放到内部维护的FIFO队列上面去。。。这里是通过state参数的值来判断的。。。然后状态的更新通过compareAndSetState以及setState方法实现。。。必须用这两个方法,因为他们都是原子的实现。。。
然后调用release方法释放锁,将会调用tryRelease方法来判断当前是否能够释放,如果返回ture的话,那么表示可以释放了,同时将会唤醒在队列上等待的线程,来继续竞争锁,如果返回false,那么表示还不行。。。
很简单吧,没用几行代码,,功能就算实现了。。。
当然这里是独占的方式。。
如果是要共享的锁,例如可以多个线程获取锁,那么就应该调用的方法是acquireShared或者acquireInterruptibly方法了,在释放的时候就应该调用releaseShared方法。。。
同理我们要实现的判断方法就应该是tryAcquireShared以及tryReleaseShared方法了。。
嗯,这里就不细说了,知道简单的该怎么用就好了。。。
有兴趣可以去读concurrent库里面的那些锁的实现。。。
java类库concurrent中最核心类型AbstractQueuedSynchronizer的学习,布布扣,bubuko.com