AQS(二):独占式锁

1、AQS属性:

以前文章提到过,看一个类的属性这个类整个的功能。

AQS中的属性:

public abstract class AbstractQueuedSynchronizer{
		
	private transient volatile Node head;

	private transient volatile Node tail;

	private volatile int state;	
}

state取值:

//节点从同步队列中取消

int CANCELLED =  1

//后继节点的线程处于等待状态,如果当前节点释放同步状态会通知后继节点,使得后继节点的线程能够运行;
int SIGNAL    = -1

//当前节点进入等待队列中
int CONDITION = -2

//表示下一次共享式同步状态获取将会无条件传播下去
int PROPAGATE = -3

//初始状态
int INITIAL = 0;

AQS的静态内部类Node: 

public abstract class AbstractQueuedSynchronizer{
		
	static final class Node {

		//标记表示节点正在共享模式中等待
		static final Node SHARED = new Node();
			   
		//标记表示节点正在独占模式下等待
		static final Node EXCLUSIVE = null;

		//节点状态
		volatile int waitStatus 

		//当前节点/线程的前驱节点
		volatile Node prev 

		//当前节点/线程的后继节点
		volatile Node next; 

		//加入同步队列的线程引用
		volatile Thread thread;

		//等待队列中的下一个节点(和Condition配合使用)
		Node nextWaiter;
	}	
}

剩下的方法都是围绕以上属性所服务的:

AQS提供的主要方法

  • getState():返回同步状态的当前值
  • setState(int newState):设置当前同步状态
  • compareAndSetState(int expect, int update):使用CAS设置当前状态,该方法能够保证状态设置的原子性
  • isHeldExclusively():当前同步器是否在独占式模式下被线程占用,一般该方法表示是否被当前线程独占
  • acquire(int arg):独占式获取同步状态,如果当前线程获取同步状态成功,则由改方法返回,否则,将会进入同步队列等待,该方法将会调用可重写的tryAcquire(int arg)方法
  • acquireInterruptibly(int arg):与acquire(int arg)相同,但是该方法响应中断,当前线程为获取到同步状态而进入到同步队列中,如果当前线程被中断,则该方法抛出InterruptedException异常并返回
  • acquireShared(int arg):共享式获取同步状态,如果当前线程未获取到同步状态,将会进入同步队列等待,与独占式的主要区别是在同一时刻可以有多个线程获取到同步状态
  • acquireSharedInterruptibly(int arg):共享式获取同步状态,响应中断
  • release(int arg):独占式释放同步状态,该方法会在释放同步状态之后,将同步队列中第一个节点包含的线程唤醒
  • releaseShared(int arg):共享式释放同步状态
  • tryAcquire(int arg):独占式获取同步状态,获取同步状态成功后,其他线程需要等待该线程释放同步状态才能获取同步状态
  • tryRelease(int arg):独占式释放同步状态
  • tryAcquireNanos(int arg, long nanos):超时获取同步状态,如果当前线程在nanos时间内没有获取到同步状态,那么将会返回false,已经获取则返回true
  • tryAcquireShared(int arg):共享式获取同步状态,返回值大于等于0表示获取成功,否则获取失败
  • tryReleaseShared(int arg):共享式释放同步状态
  • tryAcquireSharedNanos(int arg, long nanosTimeout):共享式获取同步状态,增加超时限制

2、独占式锁

2.1、获取独占式锁

调用lock()方法是获取独占式锁,获取失败就将当前线程加入同步队列,成功则线程执行。而lock()方法实际上会调用AQS的acquire()方法

acquire根据当前获得同步状态成功与否做了两件事情:

  1. 成功,则方法结束返回
  2. 失败,则先调用addWaiter()将线程加入等待队列,然后在调用acquireQueued()方法:排队再次获取锁。
    public final void acquire(int arg) {
    
    //获取同步状态成功,则直接返回。若失败则先调用addWaiter()方法再调用acquireQueued()方法
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
        }
    }

     2.2、获取独占式锁态失败:做入队操作

private Node addWaiter(Node mode) {

        // 1. 将当前线程构建成Node
        Node node = new Node(Thread.currentThread(), mode);
     
        // 2. 当前尾节点是否为null
        Node pred = tail;
        if (pred != null) {
            // 当前同步队列尾节点不为null,则将当前节点尾插入的方式插入同步队列中
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        // 当前同步队列尾节点为null,说明当前线程是第一个加入同步队列进行等待的线程
        enq(node);
        return node;
}

private Node enq(final Node node) {
	
	//自旋的过程(for (;;))
    for (;;) {
        Node t = tail;
        if (t == null) {
            //1. 构造头结点
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            // 2. CAS操作设置尾节点,CAS操作失败后负责自旋进行尝试会在for (;;)for死循环中不断尝试,直至成功return返回为止。
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

在同步队列中的节点(线程)会做什么事情了来保证自己能够有机会获得独占式锁了?自旋:acquireQueued

 2.3、入队列后,线程排队获取独占式锁:acquireQueued

final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                // 获取当前节点的先驱节点
                final Node p = node.predecessor();
                // 2.1 如果当前节点的先驱节点是头结点并且成功获取同步状态,即可以获得独占式锁
                if (p == head && tryAcquire(arg)) {
                    //获取锁成功,出队操作(队列头指针用指向当前节点)
                    setHead(node);
                    //释放前驱节点
                    p.next = null;
                    failed = false;
                    return interrupted;
                }
                // 2.2 获取锁失败,线程进入等待状态,等待获取独占式锁
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
					//如果等待过程中被中断过,就将interrupted标记为true
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
}
//做出队操作:
private void setHead(Node node) {
        head = node;
        node.thread = null;
        node.prev = null;
}

//就进入waiting状态,直到被unpark()
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
	
	//拿到前驱的状态
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
       //如果已经告诉前驱拿完号后通知自己一下,那就可以安心休息了
        return true;
    if (ws > 0) {
		/*
         * 如果前驱放弃了,那就一直往前找,直到找到最近一个正常等待的状态,并排在它的后边。
         * 注意:那些放弃的结点,由于被自己“加塞”到它们前边,它们相当于形成一个无引用链,稍后就会被GC回收
         */
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
	 //如果前驱正常,那就把前驱的状态设置成SIGNAL,告诉它拿完号后通知自己一下。有可能失败,人家说不定刚刚释放完呢!
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

private final boolean parkAndCheckInterrupt() {
	//调用park()使线程进入waiting状态
	LockSupport.park(this);
	//如果被唤醒,查看自己是不是被中断的
	return Thread.interrupted();
}

2.4、释放独占式锁:release()


public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;//找到头结点
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);//唤醒等待队列里的下一个线程
        return true;
    }
    return false;
}

//释放锁
protected boolean tryRelease(int arg) {
	throw new UnsupportedOperationException();
}

//唤醒等待队列里的下一个线程
private void unparkSuccessor(Node node) {
    //当前线程所在的结点状态
    int ws = node.waitStatus;
    if (ws < 0)//置零当前线程所在的结点状态,允许失败。
        compareAndSetWaitStatus(node, ws, 0);

    Node s = node.next;//找到下一个需要唤醒的结点(后继节点)
    if (s == null || s.waitStatus > 0) {//如果后继节点为空或已取消
        s = null;
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)//从这里可以看出,<=0的结点,都是还有效的结点。
                s = t;
    }
    if (s != null)
        LockSupport.unpark(s.thread);//唤醒
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
未来社区的建设背景和需求分析指出,随着智能经济、大数据、人工智能、物联网、区块链、云计算等技术的发展,社区服务正朝着数字化、智能化转型。社区服务渠道由分散向统一融合转变,服务内容由通用庞杂向个性化、服务导向转变。未来社区将构建数字化生态,实现数据在线、组织在线、服务在线、产品智能和决策智能,赋能企业创新,同时注重人才培养和科研平台建设。 规划设计方面,未来社区将基于居民需求,打造以服务为中心的社区管理模。通过统一的服务平台和应用,实现服务内容的整合和优化,提供灵活多样的服务方,如推送、订阅、热点等。社区将构建数据与应用的良性循环,提高服务效率,同时注重生态优美、绿色低碳、社会和谐,以实现幸福民生和产业发展。 建设运营上,未来社区强调科学规划、以人为本,创新引领、重点突破,统筹推进、整体提升。通过实施院落+社团自治工程,转变政府职能,深化社区自治法制化、信息化,解决社区治理中的重点问题。目标是培养有活力的社会组织,提高社区居民参与度和满意度,实现社区治理服务的制度机制创新。 未来社区的数字化解决方案包括信息发布系统、服务系统和管理系统。信息发布系统涵盖公共服务类和社会化服务类信息,提供政策宣传、家政服务、健康医疗咨询等功能。服务系统功能需求包括办事指南、公共服务、社区工作参与互动等,旨在提高社区服务能力。管理系统功能需求则涉及院落管理、社团管理、社工队伍管理等,以实现社区治理的现代化。 最后,未来社区建设注重整合政府、社会组织、企业等多方资源,以提高社区服务的效率和质量。通过建立社区管理服务综合信息平台,提供社区公共服务、社区社会组织管理服务和社区便民服务,实现管理精简、高效、透明,服务快速、便捷。同时,通过培育和发展社区协会、社团等组织,激发社会化组织活力,为居民提供综合性的咨询和服务,促进社区的和谐发展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值