前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >99%的人都知道用AQS实现互斥锁,你还在做那1%?

99%的人都知道用AQS实现互斥锁,你还在做那1%?

作者头像
AI码师
发布2022-09-19 11:49:05
2830
发布2022-09-19 11:49:05
举报

什么是队列同步器

我们在并发包中用到的锁或者其他同步组件都是基于AQS构建的。

AQS 里面提供了三个基础方法:setState(),getState(),compareAndSetState();

实现者(自己扩展锁或开发一个同步组件)通过调用这几个方法就可以保证线程安全的,这也是DougLea最终的期望。

同步器既可以支持独占式获取锁,也支持获取共享锁。

锁与同步器之间的关系:锁是面向使用者的,它对用户隐藏了底层的实现细节;

同步器是面向锁的,它给锁的实现提供了基础服务。

同步基础方法

getState()

获取当前同步状态,返回一个整形数值

setState()

设置状态,接受一个整形数值

compareAndSetState()

利用CAS 线程安全的设置状态

同步器中可重写的方法

tryAccquire()

独占式获取锁,重写时需要查询当前状态并且判断同步状态是否符合预期,然后再通过CAS设置状态值

tryRelease()

独占式释放锁

tryAccquireShared()

共享式获取同步状态,返回大于等于0 表示获取成功

tryReleaseShared()

共享式释放同步状态

isHeldExclusively()

当前锁是否被当前线程独占

同步器中的模版方法

accquire()

独占式获取同步状态如果获取锁成功,则返回,否则进入到同步队列等待,该方法会调用tryAccquire()尝试获取锁,

acquireInterruptibly()

该方法会响应中断,

tryAcquireNanos()

在accquireInterruptibly()基础上加了超时时间,如果在指定时间范围内没有拿到,则返回false

acquireShared()

共享式获取同步状态,当前锁会被多个线程共享

acquireSharedInterruptibly()

响应中断

tryAcquireSharedNanos()

在accquireSharedInterruptibly()基础上添加超时时间

release()

释放独占锁

releaseShared()

释放共享锁

getQueuedThreads()

获取等待在同步队列上的集合

实现一个互斥锁

首先给大家一个思路,实现互斥锁的基本流程

  • 继承Lock 接口,对外提供统一的获取锁和释放锁的方法
  • 在内部实现一个AQS,通过AQS来实现锁的获取和释放
代码语言:javascript
复制
package com.ams.thread.lesson5;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * 关注微信公众号"AI码师"获取项目源码及2021面试题一套
 *
 * @author: AI码师
 * Date: 2021/12/30 6:09 上午
 * Description:
 */
public class MyMutexLock implements Lock {
    private final LockAQS lockAQS = new LockAQS();

    @Override
    public void lock() {
        lockAQS.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        lockAQS.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return lockAQS.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return lockAQS.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        lockAQS.release(1);
    }

    @Override
    public Condition newCondition() {
        return lockAQS.newCondition();
    }

    private static class LockAQS extends AbstractQueuedSynchronizer {
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        /**
         * 重新获取锁的逻辑,只有当前同步状态为0,才允许获取成功
         *
         * @param arg
         * @return
         */
        @Override
        protected boolean tryAcquire(int arg) {
            // 通过cas机制去设置新值,设置成功,则代表同步状态为0
            if (compareAndSetState(0, 1)) {
                return true;
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            // 首先判断当前state 如果当前状态值不是1 说明当前锁没有被人获取
            if (getState() != 1) {
                return false;
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        Condition newCondition() {
            return new ConditionObject();
        }
    }

}

使用互斥锁

代码语言:javascript
复制
package com.ams.thread.lesson5;

import cn.hutool.core.thread.ThreadUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 关注微信公众号"AI码师"获取项目源码及2021面试题一套
 *
 * @author: AI码师
 * Date: 2021/12/30 6:08 上午
 * Description:
 */
@Slf4j
public class Example16 {
private static MyMutexLock myMutexLock = new MyMutexLock();

    public static void main(String[] args) {
        new Thread(new Thread1()).start();
        new Thread(new Thread2()).start();
    }
    static class Thread1 implements Runnable {

        @Override
        public void run() {
            myMutexLock.lock();
            log.info("Thread1 获取到锁");
            ThreadUtil.sleep(5000);
            myMutexLock.unlock();
        }
    }
    static class Thread2 implements Runnable {

        @Override
        public void run() {
            myMutexLock.lock();
            log.info("Thread2 获取到锁");
            ThreadUtil.sleep(5000);
            myMutexLock.unlock();
        }
    }
}

关注公众号领取2022最新面试题一套和项目源码

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-01-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 乐哥聊编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是队列同步器
  • 同步基础方法
    • getState()
      • setState()
        • compareAndSetState()
        • 同步器中可重写的方法
          • tryAccquire()
            • tryRelease()
              • tryAccquireShared()
                • tryReleaseShared()
                  • isHeldExclusively()
                  • 同步器中的模版方法
                    • accquire()
                      • acquireInterruptibly()
                        • tryAcquireNanos()
                          • acquireShared()
                            • acquireSharedInterruptibly()
                              • tryAcquireSharedNanos()
                                • release()
                                  • releaseShared()
                                    • getQueuedThreads()
                                    • 实现一个互斥锁
                                    领券
                                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档