失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > AQS独占式获取同步状态和释放同步状态(源码阅读笔记)

AQS独占式获取同步状态和释放同步状态(源码阅读笔记)

时间:2022-08-01 21:28:49

相关推荐

AQS独占式获取同步状态和释放同步状态(源码阅读笔记)

1.Lock接口的实现基本都是通过聚合了一个同步器的子类来完成线程访问控制的,例如ReentrantLock的实现

abstract static class Sync extends AbstractQueuedSynchronizerstatic final class NonfairSync extends Syncstatic final class FairSync extends Sync复制代码

2.公平锁和非公平锁的实现分别依赖FairSync和NonfairSync重写了AQS的一些方法,以及调用了AQS的模板方法来独占式获取同步状态和独占式释放同步状态

//非公平获取同步状态,调用了AQS的模板方法acquire(1);final void lock() {if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}//公平获取同步状态,调用了AQS的模板方法acquire(1);final void lock() {acquire(1);}复制代码

3.AQS的模板方法acquire代码实现

//独占式获取同步状态public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}tryAcquire(arg):如果尝试获取同步状态失败,就调用addWaiter(Node node)方法将当前线程包装为一个node节点插入同步队列尾部。如果追加成功则自旋的检查node的前驱是不是hade节点,如果是hade节点就尝试获取同步状态. 复制代码

3.1 addWaiter()方法:

/**将当前线程包装成一个node,判断尾节点是不是null,如果不是null则将尾节点赋值给node的前驱节点然后cas设置node为尾节点,如果设置成功则将node指向原来尾巴节点的后继,并返回node*/private Node addWaiter(Node mode) {Node node = new Node(Thread.currentThread(), mode);Node pred = tail;if (pred != null) {node.prev = pred;if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}enq(node);return node;}/**如果尾节点是null,说明头节点也是null,就循环cas设置一个新的node为头节点,然后将新的头节点赋值给尾节点(头尾是一个节点)循环下次进入的时候尾节点就不是null了,就将当前线程包装的node,循环cas设置为尾节点,并且和新new的头节点管理*/private Node enq(final Node node) {for (;;) {Node t = tail;if (t == null) { // Must initializeif (compareAndSetHead(new Node()))tail = head;} else {node.prev = t;if (compareAndSetTail(t, node)) {t.next = node;return t;}}}}总结上面两个方法就是先cas设置一次尾节点 如果成功则返回node,如果失败则循环的设置 直到设置成功才返回复制代码

3.2acquireQueued()方法:

/** 循环判断node的前驱节点是不是头节点,如果是头节点就尝试获取同步状态,如果不是头节点或者获取同步状态失败则线程进入等待状态直到node是头节点并获取同步状态成功-则将node设置为头节点然后将原来的头节点从链表断开,然后从方法返回 shouldParkAfterFailedAcquire,parkAndCheckInterrupt,cancelAcquire 这三个方法暂时还没看final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)cancelAcquire(node);}}复制代码

4.简单自定义同步组件(要求在同一时刻只可以有一个线程可以获得同步状态)

/*** @author qinc* @version V1.0* @Description: Lock接口的实现基本都是通过聚合了一个同步器的子类来完成线程访问控制的* @Date /4/4 11:51*/public class MonopolyLock implements Lock {private static class Sync extends AbstractQueuedSynchronizer{//重新获取同步状态方法tryAcquire@Overrideprotected boolean tryAcquire(int arg) {final Thread current = Thread.currentThread();int c = getState();if (c==0){//可以获取同步状态if (compareAndSetState(c,1)){setExclusiveOwnerThread(current);System.out.println("独占获取同步状态成功!");return true;};}return false;}//重写释放同步状态方法tryRelease。独占锁,只有获得了锁才可以释放所以直接不需要cas直接setState就可以@Overrideprotected boolean tryRelease(int arg) {int c = getState();if (c==1){setState(0);setExclusiveOwnerThread(null);System.out.println("独占释放同步状态成功!");return true;}return false;}}Sync sync = new Sync();@Overridepublic void lock() {//独占式获取同步状态(调用AQS的模板方法)sync.acquire(1);}@Overridepublic void unlock() {//独占是释放同步状态(调用AQS的模板方法)sync.release(1);}}测试方法:/*** @Description: 测试自定义同步组件* @author qinc20* @version V1.0* @Date/4/4 12:54*/public class MonopolyLockTest {public static void main(String args[]){ExecutorService executorService = Executors.newFixedThreadPool(20);MonopolyLock lock= new MonopolyLock();for (int i=0;i<20;i++){executorService.submit(new Task(lock));}executorService.shutdown();}}class Task implements Runnable{MonopolyLock lock;Task(MonopolyLock lock){this.lock=lock;}@Overridepublic void run() {while (true){lock.lock();try {Thread.sleep(2000);System.out.println(Thread.currentThread().getName()+" do SomeThing!!");Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}finally {lock.unlock();}}}}执行结果:复制代码

如果觉得《AQS独占式获取同步状态和释放同步状态(源码阅读笔记)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。