java类库concurrent中最核心类型AbstractQueuedSynchronizer的学习

首先,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

java类库concurrent中最核心类型AbstractQueuedSynchronizer的学习

上一篇:【python】理解生成器及yield


下一篇:java实现动态智能数组,将旧数组copy到新数组