AbstractQueuedSynchronizer简单使用

Stella981
• 阅读 729

AQS是JUC中很多同步组件的构建基础,简单来讲,它内部实现主要是状态变量state和一个FIFO队列来完成,同步队列的头结点是当前获取到同步状态的结点,获取同步状态state失败的线程,会被构造成一个结点(或共享式或独占式)加入到同步队列尾部(采用自旋CAS来保证此操作的线程安全),随后线程会阻塞;释放时唤醒头结点的后继结点,使其加入对同步状态的争夺中。

  AQS为我们定义好了顶层的处理实现逻辑,我们在使用AQS构建符合我们需求的同步组件时,只需重写tryAcquire,tryAcquireShared,tryRelease,tryReleaseShared几个方法,来决定同步状态的释放和获取即可,至于背后复杂的线程排队,线程阻塞/唤醒,如何保证线程安全,都由AQS为我们完成了,这也是非常典型的模板方法的应用。AQS定义好顶级逻辑的骨架,并提取出公用的线程入队列/出队列,阻塞/唤醒等一系列复杂逻辑的实现,将部分简单的可由使用者决定的操作逻辑延迟到子类中去实现。

package com.abstractqueuesynchronizer;

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

public class SelfAbstractQueueSynchronizer {


    //继承AbstractQueuedSynchronizer类
    private static class Syn extends AbstractQueuedSynchronizer {
        
        private static final long serialVersionUID = 1L;

        //是否拥有锁
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }
        
        //获取锁
        public boolean tryAcquire(int acquires) {
            if(compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }
        
        //释放所
        protected boolean tryRelease(int releases) {
            if(getState() == 0) 
                throw new IllegalMonitorStateException();
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
    }
    
    private final Syn syn = new Syn();
    
    public void lock() {
        syn.acquire(1);
    }
    
    public boolean tryLock() {
        return syn.tryAcquire(1);
    }
    
    public void unlock() {
        syn.release(1);
    }
    
    public boolean isLocked() {
        return syn.isHeldExclusively();
    }
}

测试

package com.abstractqueuesynchronizer;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class Main {

    private static CyclicBarrier barrier = new CyclicBarrier(31);
    private static int a = 0;
    private static SelfAbstractQueueSynchronizer test = new SelfAbstractQueueSynchronizer();
    
    public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
        
        for(int i = 0; i < 30; i++) {
            Thread t = new Thread(new Runnable(){

                @Override
                public void run() {
                    for(int i = 0; i < 1000; i++) {
                        unlockIncrement();
                    }
                    try {
                        barrier.await();
                    } catch (Exception e) {
                        e.printStackTrace();;
                    }
                }

            });
            t.start();
        }
        
        barrier.await();
        System.out.println("unlock model a= " + a);
        
        System.out.println("##########################");
        
        barrier.reset();
        a = 0;
        for(int i = 0; i < 30; i++) {
            Thread t = new Thread(new Runnable(){
                @Override
                public void run() {
                    for(int i = 0; i < 1000; i++ ) {
                        lockIncrement();
                    }
                    
                    try {
                        barrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
                
            });
            t.start();
        }
        
        barrier.await();
        System.out.println("lock model a= " + a);
        
    }
    
    public static void unlockIncrement() {
        a++;
    }
    
    public static void lockIncrement() {
        test.lock();
        a++;
        test.unlock();
    }
    
}
点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
java并发数据结构
一.BlockingDeque阻塞双端队列(线程安全):注意ArrayDeque和LinkedList仅仅扩展了Deque,是非阻塞类型的双端队列。BlockingQueue单向队列,其内部基于ReentrantLockCondition来控制同步和"阻塞"/"唤醒"的时
Stella981 Stella981
3年前
OpenWrt mesh组网设置
Mesh组网的主要是利用8021.s协议创建mesh结点结点之间进行数据同步kvr协议负责终端在各结点之间漫游同步操作三频路由器mesh结点数据同步都是走一个频段其他的数据走宁外两个频段,所以效果会好些一般的路由器只有5GHZ主要是5.2GHZ频段,2.4G频段本文主要是介绍路由器刷了Openwrt之后Mesh组网的设置,达到无缝
Wesley13 Wesley13
3年前
Java并发之AQS详解
一、概述  谈到并发,不得不谈ReentrantLock;而谈到ReentrantLock,不得不谈AbstractQueuedSynchronizer(AQS)!  类如其名,抽象的队列式的同步器,AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock/Semaphore/CountD
Wesley13 Wesley13
3年前
Java并发包源码学习:CLH同步队列及同步资源获取与释放
本篇学习目标回顾CLH同步队列的结构。学习独占式资源获取和释放的流程。CLH队列的结构我在Java并发包源码学习系列:AbstractQueuedSynchronizer同步队列与Node节点已经粗略地介绍了一下CLH的结构,本篇主要解析该同步队列的相关操作,因此在这边再回顾一下:AQS通过
Stella981 Stella981
3年前
ReetrantLock源码分析
ReentrantLock类的大部分逻辑,都是其均继承自AQS的内部类Sync实现的啥是AQS:Java并发编程核心在于java.concurrent.util包而juc当中的大多数同步器实现都是围绕着共同的基础行为,比如「等待队列、条件队列、独占获取、共享获取」等,而这个行为的抽象就是基于AbstractQueuedSynchron
Wesley13 Wesley13
3年前
AQS之工作原理
前面一章LZ简单的介绍了下AbstractQueuedSynchronizer(AQS)以及AQS中提供的一些模板方法和作用,这一章LZ将用一个简单的实例来介绍下AQS中独占锁的工作原理。独占锁顾名思义就是在同一时刻只能有一个线程能获取到锁,而其它需要获取这把锁的线程将进入到同步队列中等待获取到了锁的线程释放这把锁,只有获取锁的线程释放了锁,同步队列中的线程
Wesley13 Wesley13
3年前
AQS 原理剖析
!(https://images.ytao.top/20200627230025.jpg)AQS即AbstractQueuedSynchronizer类称作队列同步器,是构建其他同步器的一个重要的基础框架,同步器自身是没有实现任何同步接口。它是通过控制一个int类型的state变量来表示同步状态,使用一个内置的FIFO(先进先出)
Wesley13 Wesley13
3年前
Java中的队列同步器AQS
一、AQS概念  1、队列同步器是用来构建锁或者其他同步组件的基础框架,使用一个int型变量代表同步状态,通过内置的队列来完成线程的排队工作。  2、下面是JDK8文档中对于AQS的部分介绍  publicabstractclassAbstractQueuedSynchronizerextendsAbstract
Wesley13 Wesley13
3年前
Java并发中常用同步工具类
同步工具类可以是任何一个对象,只要它根据其自身的状态来协调线程控制流。阻塞队列(BlockingQueue)可以作为同步工具类,其他类型的同步工具类还包括信号量(Semaphore),栅栏(Barrier)以及闭锁(Latch)。在平台类库中还包含其他一些同步工具类的类,如果这些类还无法满足需要,那么可以创建自己的同步工具类。闭锁Latch
Wesley13 Wesley13
3年前
Java核心技术卷一基础知识
第14章多线程本章内容:什么是线程中断线程线程状态线程属性同步阻塞队列线程安全的集合Collable与Future执行器同步器线程与Swing1.通