博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AQS(AbstractQueuedSynchronizer)应用案例-02
阅读量:6416 次
发布时间:2019-06-23

本文共 4085 字,大约阅读时间需要 13 分钟。

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.

转载于:https://www.cnblogs.com/coding400/p/10453783.html

你可能感兴趣的文章
JavaScript简介
查看>>
SQL Server附加数据库拒绝访问解决方法汇总
查看>>
SM2算法原理及实现
查看>>
RHCA教材翻译计划
查看>>
js-小括号在不同场合下的作用
查看>>
我的友情链接
查看>>
kvm中虚拟机的硬盘扩容
查看>>
Android (Launch Mode) 四种启动模式
查看>>
透视学理论(二)
查看>>
Dubbo/HSF在Service Mesh下的思考和方案
查看>>
Django form表单
查看>>
CTYL-9.14(tomcat端口与阿里云安全组,域名与tomcat配置,域名与反向代理)
查看>>
Java 多线程相关问题记录
查看>>
LNMP架构介绍、MySQL安装、PHP安装、 Nginx介绍
查看>>
简单的Spark+Mysql整合开发
查看>>
阿里java面试经验大汇总(附阿里职位需求)
查看>>
Python全套零基础视频教程+软件2018最新编程视频!
查看>>
内存管理之1:x86段式内存管理与保护模式
查看>>
20180925上课截图
查看>>
IO输入/输出流的简单总结
查看>>