栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JUC-AQS面试(AbstractQuenedSynchronizer)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JUC-AQS面试(AbstractQuenedSynchronizer)

Java.util.concurrent(J.U.C)大大提高了并发性能,AQS是JUC的核心,是阻塞式锁相关的同步器工具的框架,是一个主要用来构建锁和同步器的抽象类。全称AbstractQuenedSynchronizer 意思就是抽象队列同步器。

AQS特点

用state属性来表示资源的状态(分独步模式和共享模式),子类需要定义如何维护这个状态,控制如果获取锁和释放锁

getState-获取state状态

setState-设置state状态

compareAndSetState-乐观锁机制设置state状态

独占模式:只有一个线程能访问资源

共享模式:可以允许多个线程访问资源

提供基于FIFO等待队列,类似Monitor的EntryList

条件变量来实现等待,唤醒机制

子类主要实现这样的一些方法(默认抛出UnsupportedOperationException)

tryAcquire //尝试获取锁

tryRelease //尝试释放锁

tryAcquireShared

tryReleaseShared

isHeldExclusively //是否持有独占锁

获取锁的姿势:

//如果获取锁失败
if(!tryAcquire(arg)){
	//入队,可以选择阻塞当前线程 
}

释放锁的姿势:

//如果释放锁失成功
if(tryRelease(arg)){
	//让阻塞的线程恢复运行
}
AQS原理

AQS核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制。

这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中,

CLH(Craig,Landin,and Hagersten)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS 是将每条请求共享资源的线程封装成一个 CLH 锁队列的一个结点(Node)来实现锁的分配。

CountDownLatch (倒计时器)

用来控制一个或者多个线程等待多个线程。

它默认构造 AQS 的 state 值为 count ,维护了一个计数器 cnt,每次调用 countDown() 方法会让计数器的值减 1,减到 0 的时候,那些因为调用 await() 方法而在等待的线程就会被唤醒。

StampedLock

JDK8加入,进一步优化读性能,在读锁或者写锁的时候都需要配合【戳】使用

不支持条件变量、不支持可重入

//加解读锁
long stamp = lock.readLock();
lock.unlockRead(stamp);
//加解写锁
long stamp = lock.writeLock();
lock.unlockWrite(stamp);

乐观读,StampedLock支持tryOptimisticRead()方法,读取完毕后要再一次进行戳检验,如果校验通过,表示这期间确实没有写操作,数据可以安全使用,若校验没通过需要重新获取读锁确保数据安全  

long stamp = lock.tryOptimisticRead();//戳
//验戳
if(!lock.validate(stamp)){
	//锁升级
}
private int data;
private final StampedLock lock = new StampedLock();
public DataContainerStamped(int data){
    this.data = data;
}
public int read(){
    long stamp = lock.tryOptimisticRead();
    sleep(1);
    //乐观读
    if(lock.validate(stamp)){
        return data;
    }
    //锁升级,读锁
    try{
        stamp = lock.readLock();
        sleep(1);
        return data;
    }finally{
        lock.unlockRead(stamp);
    }
}
public void write(){
    long stamp = lock.writeLock();
    try{
        sleep(2);
        this.data = newData
    }finally{
        lock.unlockWriter(stamp);
    }
}
Semaphore

信号量, 可以控制对互斥资源的访问线程数 ,限制同步队列的容量

 public static void main(String[] args) {
        //创建semaphore对象
        Semaphore semaphore = new Semaphore(3);
        //创建线程 同时运行
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            new Thread(()->{
                //获得许可
                try {
                    semaphore.acquire();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                   System.out.println(finalI+"running....");
					sleep(1);
                   System.out.println(finalI+ "end....");
                    } finally {
                        semaphore.release();
                }
            }).start();
        }
    }

CyclicBarrier

用来控制多个线程互相等待,只有当多个线程都到达时,这些线程才会继续执行。

和 CountdownLatch 相似,都是通过维护计数器来实现的。线程执行 await() 方法之后计数器会减 1,并进行等待,直到计数器为 0,所有调用 await() 方法而在等待的线程才能继续执行。

CyclicBarrier 和 CountdownLatch 的一个区别是,CyclicBarrier 的计数器通过调用 reset() 方法可以循环使用,所以它才叫做循环屏障。

CyclicBarrier 有两个构造函数,其中 parties 指示计数器的初始值,barrierAction 在所有线程都到达屏障的时候会执行一次。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/750797.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号