阿里三面最后一问:解释一下Java并发AQS的独占锁模式

概述

稍微对并发源码了解的朋友都知道,很多并发工具如ReentrantLock、CountdownLatch的实现都是依赖AQS, 全称

AbstractQueuedSynchronizer。

AQS是一种提供了原子式管理同步状态、阻塞和唤醒线程功能以及队列模型的简单框架。一般来说,同步工具实现锁的控制分为独占锁和共享锁,而AQS提供了对这两种模式的支持。

独占锁: 也叫排他锁,即锁只能由一个线程获取,若一个线程获取了锁,则其他想要获取锁的线程只能等待,直到锁被释放。比如说写锁,对于写操作,每次只能由一个线程进行,若多个线程同时进行写操作,将很可能出现线程安全问题,比如jdk中的ReentrantLock。

共享锁: 锁可以由多个线程同时获取,锁被获取一次,则锁的计数器+1。比较典型的就是读锁,读操作并不会产生副作用,所以可以允许多个线程同时对数据进行读操作,而不会有线程安全问题,当然,前提是这个过程中没有线程在进行写操作,比如ReadWriteLock和CountdownLatch。

本文重点讲解下AQS对独占锁模式的支持。

自定义独占锁例子

首先我们自定义一个非常简单的独占锁同步器demo, 来了解下AQS的使用。

publicclassExclusiveLockimplementsLock{

    // 同步器,继承自AQSprivatestaticclassSyncextendsAbstractQueuedSynchronizer{

        // 重写获取锁的方式@OverrideprotectedbooleantryAcquire(int acquires){
            assert acquires == 1;
            // cas的方式抢锁if(compareAndSetState(0, 1)) {
                // 设置抢占锁的线程为当前线程
                setExclusiveOwnerThread(Thread.currentThread());
                returntrue;
            }
            returnfalse;
        }

        @OverrideprotectedbooleantryRelease(int releases){
            assert releases == 1;

            if (getState() == 0) {
                thrownew IllegalMonitorStateException();
            };
            //设置抢占锁的线程为null
            setExclusiveOwnerThread(null);
            // 释放锁
            setState(0);
            returntrue;
        }
    }

    privatefinal Sync sync = new Sync();

    @Overridepublicvoidlock(){
        sync.acquire(1);
    }

    @Overridepublicvoidunlock(){
        sync.release(1);
    }

    @OverridepublicvoidlockInterruptibly()throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    @OverridepublicbooleantryLock(){
        return sync.tryAcquire(1);
    }

    @OverridepublicbooleantryLock(long time, TimeUnit unit)throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }
    
    @Overridepublic Condition newCondition(){
        returnnull;
    }
}

这里是一个不可重入独占锁类,它使用值0表示未锁定状态,使用值1表示锁定状态。

验证:

publicstaticvoidmain(String[] args) throws InterruptedException {
        ExclusiveLock exclusiveLock = new ExclusiveLock();


        new Thread(() -> {
            try {
                exclusiveLock.lock();
                System.out.println("thread1 get lock");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                exclusiveLock.unlock();
                System.out.println("thread1 release lock");
            }

        }).start();

        new Thread(() -> {
            try {
                exclusiveLock.lock();
                System.out.println("thread2 get lock");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                exclusiveLock.unlock();
                System.out.println("thread2 release lock");
            }

        }).start();

        Thread.currentThread().join();
    }

这样一个很简单的独占锁同步器就实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值