继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

AQS

都要好好的ming
关注TA
已关注
手记 6
粉丝 0
获赞 0

锁在不同角度上进行划分:  如何实现自旋锁  如何实现可重入锁:一个线程的多个流程能不能重复获取同一个把锁


Lock体系:

ReentrantLock   是一种显示锁,需要手动加锁和解锁 并且ReentrantLock 是可重入锁  ,并且可以通过构造函数 指定创建的ReentrantLock 锁是否为公平锁;

什么是可重入:一个线程的多个流程都能够获取到同一把锁。


ReentrantLock 可重入锁的源码分析


AQS 源码

AQS 特性:

Java.concurrent.util当中同步器的实现如Lock,Latch,Barrier等,都是基于AQS框架实现

  • 一般通过定义内部类Sync继承AQS

  • 将同步器所有调用都映射到Sync对应的方法

AQS内部维护属性volatile int state (32位)    该变量用于记录 锁被加了多少次  和 被释放了多少次等等; state表示资源的可用状态

State三种访问方式    实现可重入

  • getState()、setState()、compareAndSetState()

AQS定义两种资源共享方式        exclusiveOwnerThread   实现 共享/独占


  • Exclusive-独占,只有一个线程能执行,如ReentrantLock 

  • Share-共享,多个线程可以同时执行,如Semaphore/CountDownLatch

AQS定义两种队列      :通过内部类 Node 实现

  • 同步等待队列   数据结构为 双向链表

  • 条件等待队列   数据结构为 单向链表

Node结点是对每一个访问同步代码的线程的封装,其包含了需要同步的线程本身以及线程的状态,如是否被阻塞,是否等待唤醒,是否已经被取消等。 

变量waitStatus则表示当前被封装成Node结点的等待状态,共有4种取值cancelled(取消)、signal(标志)、condition(条件)、propagate(传播)。

  • CANCELLED:值为1,在同步队列中等待的线程等待超时或被中断,需要从同步队列中取消该Node的结点,其结点的waitStatus为CANCELLED,即结束状态,进入该状态后的结点将不会再变化。

  • SIGNAL:值为-1,被标识为该等待唤醒状态的后继结点,当其前继结点的线程释放了同步锁或被取消,将会通知该后继结点的线程执行。说白了,就是处于唤醒状态,只要前继结点释放锁,就会通知标识为SIGNAL状态的后继结点的线程执行。 标志为下个等待被唤醒的线程节点

  • CONDITION:值为-2,与Condition相关,该标识的结点处于条件队列中,结点的线程等待在Condition上,当其他线程调用了Condition的signal()方法后,CONDITION状态的结点将从条件队列转移到同步队列中,等待获取同步锁。

  • PROPAGATE:值为-3,与共享模式相关,在共享模式中,该状态标识结点的线程处于可运行状态。

AQS中同步队列采用的是用双向链表保存,用prve和next相互链接。

AQS中条件队列是使用单向列表保存的,用nextWaiter来连接。同步队列和条件队列并不是使用的相同的数据结构。



 static final class Node {
        static final AbstractQueuedSynchronizer.Node SHARED = new AbstractQueuedSynchronizer.Node(); //声明共享模式
        static final AbstractQueuedSynchronizer.Node EXCLUSIVE = null;  // 声明独享模式
        // 等待状态标志位
		static final int CANCELLED = 1;
        static final int SIGNAL = -1;
        static final int CONDITION = -2;
        static final int PROPAGATE = -3;
        volatile int waitStatus; // waitStatus是当前节点的一个等待状态标志位,该标志位决定了该节点在当前情况下处于何种状态。
        volatile AbstractQueuedSynchronizer.Node prev; //前继节点
        volatile AbstractQueuedSynchronizer.Node next; //后继节点    通过前继节点和后继节点来实现 同步队列
        volatile Thread thread;	// 线程
        AbstractQueuedSynchronizer.Node nextWaiter;	//下一个等待的线程   通过该节点实现条件队列 

        final boolean isShared() { // 判断该节点是否为 共享
            return this.nextWaiter == SHARED;
        }
		// 该方法用来查找前置节点是否存在,相当于为前置节点查空。
        final AbstractQueuedSynchronizer.Node predecessor() throws NullPointerException {
            AbstractQueuedSynchronizer.Node var1 = this.prev;
            if (var1 == null) {
                throw new NullPointerException();
            } else {
                return var1;
            }
        }

    	// 构造方法为空参构造,一般用于创建head节点,或者为nextWaiter设置共享标志。
		Node() {
		}
		// 构造方法用于创建一个带有条件队列的节点
		Node(Thread thread, Node mode) {
		    this.nextWaiter = mode;
	  	    this.thread = thread;
		}
		// 用于创建一个带有初始等waitStatus的节点
		Node(Thread thread, int waitStatus) {
 		   this.waitStatus = waitStatus;
	    	this.thread = thread;
		}
}

CLH同步队列采用的是双向链表队列,头部节点默认获取资源获得执行权限。后续节点不断自旋方式查询前置节点是否执行完成,

直到头部节点执行完成将自己的waitStatus状态修改以通知后续节点可以获取资源执行。CLH锁是一个有序的无饥饿的公平锁。


Condition是一个多线程间协调通信的工具类,使得某个,或者某些线程一起等待某个条件(Condition),只有当该条件具备时 ,这些等待线程才会被唤醒,从而重新争夺锁



AbstractOwnableSynchronizer  抽象独占线程同步器: 用于记录时哪一个线程获取了锁
public abstract class AbstractOwnableSynchronizer implements Serializable {
    private static final long serialVersionUID = 3737899427754241961L;
    private transient Thread exclusiveOwnerThread;     // transient用于修饰不需要序列化的字段,如果一个引用类型被transient修饰,则其反序列化的值为null,如果一个基本类型被transient修饰,则其反序列化的值为0

    protected AbstractOwnableSynchronizer() {
    }	
	// 设置独占线程
    protected final void setExclusiveOwnerThread(Thread var1) {
        this.exclusiveOwnerThread = var1;
    }
	// 获取独占线程
    protected final Thread getExclusiveOwnerThread() {
        return this.exclusiveOwnerThread;
    }
}







打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP