1.概述

  通过对AQS源码的熟悉,我们可以通过实现AQS实现自定义的锁来加深认识。

2.实现

  1.首先我们确定目标是实现一个独占模式的锁,当其中一个线程获得资源时,其他线程再来请求,让它进入队列进行公平的等待。于是,我们用  Sync 代表子类,来实现  AbstractQueuedSynchronizer

其中  tryAcquire  是们在尝试获取资源时,通过子类来判断是否成功的方法,这里需要我们自己实现(父类有默认的实现方法,是因为不需要每个子类都同时实现共享和非共享模式时获取资源的方法)。

  因为是独占锁,我们便用 state = 0 为锁无人使用, state = 1 为 锁被占用,arg参数用来表示当前获取资源的个数,独占锁只能获取一个,便先校验是否为1,接着通过CAS尝试改变state的值为1,如果成功则返回true,失败返回 false

        @Override
protected boolean tryAcquire(int arg) {
assert arg == 1;
boolean success = false;
if (compareAndSetState(0,1)){
setExclusiveOwnerThread(Thread.currentThread());
success = true;
}
return success;
}

  同样的,释放锁时,我们也只能释放一把锁,因为释放锁不会出现竞争,因此直接将state设为0即可。 setExclusiveOwnerThread 是一个设置当前持有锁的线程的引用,当释放锁时,需要将持有锁的当前线程设置为null

       @Override
protected boolean tryRelease(int arg) {
assert arg == 1;
if(arg == 0){
throw new IllegalMonitorStateException();
}
setState(0);
setExclusiveOwnerThread(null);
return true;
}

  isHeldExclusively 用来判断是否是当前线程持有锁,这里可以进行一个 == 判断即可

        @Override
protected boolean isHeldExclusively() {
return Thread.currentThread() == getExclusiveOwnerThread();
}

  

3.完整源码如下

  同步锁工具类,静态内部类Sync 实现  AbstractQueuedSynchronizer

public class CusLock {
public CusLock() {
sync = new Sync();
}
public void lock(){
sync.lock();
}
public void unlock(){
sync.unlock();
}
private final Sync sync;
static class Sync extends AbstractQueuedSynchronizer{
void lock(){
if (compareAndSetState(0,1)){
setExclusiveOwnerThread(Thread.currentThread());
}else {
acquire(1);
}
}
void unlock(){
release(1);
}
@Override
protected boolean tryAcquire(int arg) {
assert arg == 1;
boolean success = false;
if (compareAndSetState(0,1)){
setExclusiveOwnerThread(Thread.currentThread());
success = true;
}
return success;
} @Override
protected boolean tryRelease(int arg) {
assert arg == 1;
if(arg == 0){
throw new IllegalMonitorStateException();
}
setState(0);
setExclusiveOwnerThread(null);
return true;
} @Override
protected boolean isHeldExclusively() {
return Thread.currentThread() == getExclusiveOwnerThread();
}
}
}

  1. SynOrder 中 getOrder()方法中用lock.lock() 来占有锁,

  2. 打印线程相关信息

  3. 睡眠5秒

  4. 释放锁

public class SynOrder {
private CusLock lock = new CusLock(); public void getOrderNo() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "--" + SimpleDateFormat.getTimeInstance(SimpleDateFormat.FULL).format(new Date()));
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
lock.unlock();
}
}
}

  1.通过开启2个线程来对synOrder中的getOrderNo产生竞争,导致阻塞。可以清楚的见到实际上 用AQS来实现自定义的锁,在已有的concurrent包下已够用

public class Main {
public static void main(String[] args) throws InterruptedException {
SynOrder synOrder = new SynOrder();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synOrder.getOrderNo();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synOrder.getOrderNo();
}
});
System.out.println("t1:"+t1.getName());
System.out.println("t2:"+t2.getName());
t1.start();
t2.start();
Thread.currentThread().join();
}
}

4.总结

  在一些内置锁无法满足需求的情况下,ReentrantLock 可以作为一种高级工具。当需要吸血高级功能时才应该使用ReentrantLock,这些功能包括:可定时的,可轮询的、可中断的锁获取操作,公平队列、以及非块结构的锁。否则还是应该优先使用 synchronized.

AQS(AbstractQueuedSynchronizer)应用案例-02的更多相关文章

  1. 高并发第十一弹:J.U.C -AQS(AbstractQueuedSynchronizer) 组件:Lock,ReentrantLock,ReentrantReadWriteLock,StampedLock

    既然说到J.U.C 的AQS(AbstractQueuedSynchronizer)   不说 Lock 是不可能的.不过实话来说,一般 JKD8 以后我一般都不用Lock了.毕竟sychronize ...

  2. AQS(AbstractQueuedSynchronizer)介绍-01

    1.概述 AQS( AbstractQueuedSynchronizer ) 是一个用于构建锁和同步器的框架,许多同步器都可以通过AQS很容易并且高效地构造出来.如: ReentrantLock 和 ...

  3. web综合案例02

    web综合案例02 web综合案例02 web综合案例02 ... ... 内容待添加

  4. 从ReentrantLock看AQS (AbstractQueuedSynchronizer) 运行流程

    从ReentrantLock看AQS (AbstractQueuedSynchronizer) 运行流程 概述 本文将以ReentrantLock为例来讲解AbstractQueuedSynchron ...

  5. 高并发第十单:J.U.C AQS(AbstractQueuedSynchronizer) 组件:CountDownLatch. CyclicBarrier .Semaphore

    这里有一篇介绍AQS的文章 非常好: Java并发之AQS详解 AQS全名:AbstractQueuedSynchronizer,是并发容器J.U.C(java.lang.concurrent)下lo ...

  6. 5. AQS(AbstractQueuedSynchronizer)抽象的队列式的同步器

    5.1 AbstractQueuedSynchronizer里面的设计模式--模板模式 模板模式:父类定义好了算法的框架,第一步做什么第二步做什么,同时把某些步骤的实现延迟到子类去实现. 5.1.1 ...

  7. AQS(AbstractQueuedSynchronizer)解析

    AbstractQueuedSynchronizer是JUC包下的一个重要的类,JUC下的关于锁相关的类(如:ReentrantLock)等大部分是以此为基础实现的.那么我们就来分析一下AQS的原理. ...

  8. java1.8 AQS AbstractQueuedSynchronizer学习

    AQS concurrent并发包中非常重要的顶层锁类,往往用的比较多的是ReentrantLock,然而ReentrantLock的实现依赖AbstractQueuedSynchronizer在到上 ...

  9. SaltStack 部署案例 02

    远程执行 salt '*' state.sls apache '*':代表所有主机 state.sls :是一个模块 apache : 状态 ,表示需要部署的内容,后缀.sls YAML:三板斧 1. ...

随机推荐

  1. Hadoop 运行jar包时 java.lang.ClassNotFoundException: Class com.zhen.mr.RunJob$HotMapper not found

    错误如下 Error: java.lang.RuntimeException: java.lang.ClassNotFoundException: Class com.zhen.mr.RunJob$H ...

  2. Linux 网卡操作与安全初始化

    一.Linux网络相关概念和修改IP地址的方法 1.1 网卡命名方式 CENTOS6的网卡命名方式: 它会根据情况有所改变而非唯一且固定,在CENTOS6之前,网络接口使用连续号码命名: eth0. ...

  3. hibernate一级缓存和二级缓存的区别(转)

    缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能.缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事 ...

  4. HDU 6231 (K-th Number)

    题目链接:https://cn.vjudge.net/problem/HDU-6231 思路:二分+双指针: #include <stdio.h> #include <iostrea ...

  5. hdu--2111--Saving HDU(贪心)

    #include<iostream> #include<vector> #include<algorithm> using namespace std; struc ...

  6. Failed to install xxxx.apk on device 'emulator-5554!

    异常信息:[HelloAndroid] Performing com.example.helloandroid.HelloAndroid activity launch[HelloAndroid] U ...

  7. 强烈建议使用国外DNS解析域名,解决访问速度和某些访问故障!

    域名解析的基本原理是把域名翻译成IP地址,以便计算机能够进一步通信,传递网址和内容等. 域名劫持就是在劫持的网络范围内拦截域名解析的请求,分析请求的域名,把审查范围以外的请求放行,否则直接返回假的IP ...

  8. [转]为什么GOF的23种设计模式里面没有MVC?

    GoF (Gang of Four,四人组, <Design Patterns: Elements of Reusable Object-Oriented Software>/<设计 ...

  9. bzoj 3158 千钧一发 —— 最小割

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3158 \( a[i] \) 是奇数则满足条件1,是偶数则显然满足条件2: 因为如果把两个奇数 ...

  10. Dockerfile创建MySQL容器

    本文目的是创建一个MySQL的image,并且在新创建出来的容器里自动启动mysql服务接受外部连接 步骤: 1. 首先创建一个目录并在目录下创建一个Dockerfile,文件内容如下 FROM ce ...