AQS之工作原理

Wesley13
• 阅读 644

前面一章LZ简单的介绍了下AbstractQueuedSynchronizer(AQS)以及AQS中提供的一些模板方法和作用,这一章LZ将用一个简单的实例来介绍下AQS中独占锁的工作原理。独占锁顾名思义就是在同一时刻只能有一个线程能获取到锁,而其它需要获取这把锁的线程将进入到同步队列中等待获取到了锁的线程释放这把锁,只有获取锁的线程释放了锁,同步队列中的线程才能获取锁。LZ可以描述的有些绕,画图来解释下这段话的意思:

AQS之工作原理

这个图则清晰的说明了AQS中独占锁的的基本原理,下面LZ将用一段简单的代码来看看AQS中独占锁的工作原理。

public class ExclusiveDemo implements Lock {    
    // 静态内部类,自定义同步器    
    private static class Sync extends AbstractQueuedSynchronizer{        
        // 是否处于独占状态        
        @Override        
        protected boolean isHeldExclusively() {            
            return this.getState() == 1;        
        }        
        // 当状态为0时,获取锁        
        @Override        
        protected boolean tryAcquire(int arg) {           
            if(compareAndSetState(0,1)){                
                setExclusiveOwnerThread(Thread.currentThread());                
                return true;            
            }           
            return false;      
        }        
        // 释放锁,将状态设置为0        
        @Override        
        protected boolean tryRelease(int arg) {           
            if(getState() == 0) throw new IllegalMonitorStateException();                       
            setExclusiveOwnerThread(null);            
            setState(0);            
            return true;        
        }        
        // 返回一个Condition,没给Condition都包含了一个Condition队列        
        Condition newCondition() {            
            return new ConditionObject();       
        }   
    }    
    private final Sync sync = new Sync();    
    @Override    
    public void lock() {        
        sync.acquire(1);   
    }   
    @Override    
    public void lockInterruptibly() throws InterruptedException {        
        sync.acquireInterruptibly(1);    
    }   
    @Override    
    public boolean tryLock() {        
        return sync.tryAcquire(1);    
    }    
    @Override    
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {   
        return sync.tryAcquireSharedNanos(1,unit.toNanos(time));   
    }   
    @Override   
    public void unlock() {       
        sync.release(0);   
    }    
    @Override   
    public Condition newCondition() {      
        return sync.newCondition();    
    }
}

上面示例中,独占所ExclusiveDemo是一个自定义的同步组件,它在同一时刻只允许一个线程占有锁。ExclusiveDemo定义了一个静态内部类,该内部类继承了同步器并实现了独占式获取和释放同步状态。在tryAcquire方法中,通过CAS方式设置同步器状态,如果设置成功,返回true,设置失败返回false。tryRelease(int arg)方法是将同步器状态设置为0。通过上面的示例,我么可以看到,当我们在使用ExclusiveDemo的时候,我们并没有直接和同步器打交道,而是通过调用ExclusiveDemo提供的方法。这一章LZ只是简单的介绍了下AQS是如何工作的,下一章LZ分析下AQS中CHL的工作原理。


关注下面公众号,回复 1024 领取最新大厂面试资料

AQS之工作原理

点赞
收藏
评论区
推荐文章
执键写春秋 执键写春秋
3年前
notifyAll唤醒线程的范围?
今天看到开源中国上有这样一个问答:假设我有两个对象锁,对象A锁有5个线程在等待,对象B锁有3个线程在等待,对象A锁中的线程执行完,这时调用notifyAll,是唤醒了对象AB两个锁的全部的等待线程还是只唤醒了A锁的5个线程?1.方法文档解释通过看该方法文档的解释,可以得出下面结论:notifyAll()中All的含义是所有的线程,而不是所有的锁,只能唤
灯灯灯灯 灯灯灯灯
3年前
面试百度和美团,竟然问我多线程安全问题,正好撞在我知识点上
解决多线程安全问题无非两个方法synchronized和lock具体原理以及如何获取锁AQS算法本篇文章主要讲了lock的原理就是AQS算法,还有个姊妹篇讲解synchronized的实现原理也是阿里经常问的,一定要看后面的文章,先说结论:非公平锁tryAcquire的流程是:检查state字段,若为0,表示锁未被占用,那么尝试占用,若不为0,检查
Wesley13 Wesley13
3年前
java中的锁
记录一下公平锁,非公平锁,可重入锁(递归锁),读写锁,自旋锁的概念,以及一些和锁有关的java类。公平锁与非公平锁:公平锁就是在多线程环境下,每个线程在获取锁时,先查看这个锁维护的队列,如果队列为空或者自身就是等待队列的第一个,就占有锁。否则就加入到等待队列中,按照FIFO的顺序依次占有锁。非公平锁会一上来就试图占
Wesley13 Wesley13
3年前
Java并发包小结
1、Lock  Lock功能对应关键字synchrozied功能,lock和unlock方法用于加锁和释放锁。等待锁的线程加入到等待链表中,同时阻塞线程,锁释放时,从等待链表中取出等待的线程执行,取等待的线程分公平与非公平两种方式,公平方式取第一个等待的线程,非公平方式当前正在获取锁的线程可能立刻执行,而不用加入到等待队列中,排队执行。2、Con
Stella981 Stella981
3年前
Python的锁
互斥锁锁通常被用来实现对共享资源的同步访问。为每一个共享资源创建一个Lock对象,lLock()创建一个锁,初始状态是未锁定当你需要访问该资源时,调用l.acquire方法来获取锁对象(如果其它线程已经获得了该锁,则当前线程需等待其被释放),待资源访问完后,再调用l.release方法释放锁!(https:
Wesley13 Wesley13
3年前
Java中的队列同步器AQS
一、AQS概念  1、队列同步器是用来构建锁或者其他同步组件的基础框架,使用一个int型变量代表同步状态,通过内置的队列来完成线程的排队工作。  2、下面是JDK8文档中对于AQS的部分介绍  publicabstractclassAbstractQueuedSynchronizerextendsAbstract
Wesley13 Wesley13
3年前
Java多线程锁释放
Java多线程运行环境中,在哪些情况下会使对象锁释放?由于等待一个锁的线程只有在获得这把锁之后,才能恢复运行,所以让持有锁的线程在不再需要锁的时候及时释放锁是很重要的。在以下情况下,持有锁的线程会释放锁:(1)执行完同步代码块,就会释放锁。(synchronized)(2)在执行同步代码块的过程中,遇到异常而导致线程终止,锁也会被释放。(exc
Wesley13 Wesley13
3年前
Java并发编程:AQS的公平性
所谓公平是指所有线程对临界资源申请访问权限的成功率都一样,它不会让某些线程拥有优先权。通过几篇文章的分析我们知道了JDK的AQS的锁是基于CLH锁进行优化的,而其中使用了FIFO队列,也就是说等待队列是一个先进先出的队列。那是否就可以说每条线程获取锁时就是公平的呢?关于公平性,严格来说应该分成三个点来看:入队阶段、唤醒阶段以及闯入策略。友情链接:
Wesley13 Wesley13
3年前
Java 并发编程:AQS 的公平性
所谓公平是指所有线程对临界资源申请访问权限的成功率都一样,它不会让某些线程拥有优先权。通过几篇文章的分析我们知道了JDK的AQS的锁是基于CLH锁进行优化的,而其中使用了FIFO队列,也就是说等待队列是一个先进先出的队列。那是否就可以说每条线程获取锁时就是公平的呢?关于公平性,严格来说应该分成三个点来看:入队阶段、唤醒阶段以及闯入策略。友情链接:
Stella981 Stella981
3年前
AbstractQueuedSynchronizer简单使用
AQS是JUC中很多同步组件的构建基础,简单来讲,它内部实现主要是状态变量state和一个FIFO队列来完成,同步队列的头结点是当前获取到同步状态的结点,获取同步状态state失败的线程,会被构造成一个结点(或共享式或独占式)加入到同步队列尾部(采用自旋CAS来保证此操作的线程安全),随后线程会阻塞;释放时唤醒头结点的后继结点,使其加入对同步状态的争夺中。