AbstractQueuedSynchronizer简单使用
AQS是JUC中很多同步组件的构建基础,简单来讲,它内部实现主要是状态变量state和一个FIFO队列来完成,同步队列的头结点是当前获取到同步状态的结点,获取同步状态state失败的线程,会被构造成一个结点(或共享式或独占式)加入到同步队列尾部(采用自旋CAS来保证此操作的线程安全),随后线程会阻塞;释放时唤醒头结点的后继结点,使其加入对同步状态的争夺中。
AQS为我们定义好了顶层的处理实现逻辑,我们在使用AQS构建符合我们需求的同步组件时,只需重写tryAcquire,tryAcquireShared,tryRelease,tryReleaseShared几个方法,来决定同步状态的释放和获取即可,至于背后复杂的线程排队,线程阻塞/唤醒,如何保证线程安全,都由AQS为我们完成了,这也是非常典型的模板方法的应用。AQS定义好顶级逻辑的骨架,并提取出公用的线程入队列/出队列,阻塞/唤醒等一系列复杂逻辑的实现,将部分简单的可由使用者决定的操作逻辑延迟到子类中去实现。
package com.abstractqueuesynchronizer;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
public class SelfAbstractQueueSynchronizer {
//继承AbstractQueuedSynchronizer类
private static class Syn extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 1L;
//是否拥有锁
protected boolean isHeldExclusively() {
return getState() == 1;
}
//获取锁
public boolean tryAcquire(int acquires) {
if(compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
//释放所
protected boolean tryRelease(int releases) {
if(getState() == 0)
throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
}
private final Syn syn = new Syn();
public void lock() {
syn.acquire(1);
}
public boolean tryLock() {
return syn.tryAcquire(1);
}
public void unlock() {
syn.release(1);
}
public boolean isLocked() {
return syn.isHeldExclusively();
}
}
测试
package com.abstractqueuesynchronizer; import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier; public class Main { private static CyclicBarrier barrier = new CyclicBarrier(31);
private static int a = 0;
private static SelfAbstractQueueSynchronizer test = new SelfAbstractQueueSynchronizer(); public static void main(String[] args) throws InterruptedException, BrokenBarrierException { for(int i = 0; i < 30; i++) {
Thread t = new Thread(new Runnable(){ @Override
public void run() {
for(int i = 0; i < 1000; i++) {
unlockIncrement();
}
try {
barrier.await();
} catch (Exception e) {
e.printStackTrace();;
}
} });
t.start();
} barrier.await();
System.out.println("unlock model a= " + a); System.out.println("##########################"); barrier.reset();
a = 0;
for(int i = 0; i < 30; i++) {
Thread t = new Thread(new Runnable(){
@Override
public void run() {
for(int i = 0; i < 1000; i++ ) {
lockIncrement();
} try {
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} });
t.start();
} barrier.await();
System.out.println("lock model a= " + a); } public static void unlockIncrement() {
a++;
} public static void lockIncrement() {
test.lock();
a++;
test.unlock();
} }
AbstractQueuedSynchronizer简单使用的更多相关文章
- JUC锁框架_AbstractQueuedSynchronizer详细分析
AQS是JUC锁框架中最重要的类,通过它来实现独占锁和共享锁的.本章是对AbstractQueuedSynchronizer源码的完全解析,分为四个部分介绍: CLH队列即同步队列:储存着所有等待 ...
- AbstractQueuedSynchronizer的简单分析
说明:本作者是文章的原创作者,转载请注明出处:本文地址:http://www.cnblogs.com/qm-article/p/7955781.html 一.AbstractQueuedSynchro ...
- AbstractQueuedSynchronizer的简单介绍
AbstractQueuedSynchronizer简称为AQS.大多数开发者不会直接使用AQS,标准同步器类的集合能够满足绝大多数情况的需求. 1.AbstractQueuedSynchronize ...
- Java并发基础框架AbstractQueuedSynchronizer初探(ReentrantLock的实现分析)
AbstractQueuedSynchronizer是实现Java并发类库的一个基础框架,Java中的各种锁(RenentrantLock, ReentrantReadWriteLock)以及同步工具 ...
- 并发编程 20—— AbstractQueuedSynchronizer 深入分析
Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...
- Java Concurrent之 AbstractQueuedSynchronizer
ReentrantLock/CountDownLatch/Semaphore/FutureTask/ThreadPoolExecutor的源码中都会包含一个静态的内部类Sync,它继承了Abstrac ...
- Java并发包源码学习之AQS框架(四)AbstractQueuedSynchronizer源码分析
经过前面几篇文章的铺垫,今天我们终于要看看AQS的庐山真面目了,建议第一次看AbstractQueuedSynchronizer 类源码的朋友可以先看下我前面几篇文章: <Java并发包源码学习 ...
- 通过ReentrantLock源代码分析AbstractQueuedSynchronizer独占模式
1. 重入锁的概念与作用 reentrant 锁意味着什么呢?简单来说,它有一个与获取锁相关的计数器,如果已占有锁的某个线程再次获取锁,那么lock方法中将计数器就加1后就会立刻返回.当释 ...
- 从一个简单的Java单例示例谈谈并发
一个简单的单例示例 单例模式可能是大家经常接触和使用的一个设计模式,你可能会这么写 public class UnsafeLazyInitiallization { private static Un ...
随机推荐
- Dump文件的生成
一.Windows系统的任务管理器里抓dump 启动任务管理器,选中某个进程,右键,弹出菜单"创建转储文件" 注意事项: 当你在64位Windows系统上抓32位进程的dmup文件 ...
- 19 如何在String和Byte[]对象之间进行转换?
- 如何将数组中的元组包转化为字典通过json序列化给前端
- 关于富文本复制word,里面掺杂图片上传的问题
图片的复制无非有两种方法,一种是图片直接上传到服务器,另外一种转换成二进制流的base64码目前限chrome浏览器使用首先以um-editor的二进制流保存为例:打开umeditor.js,找到UM ...
- BZOJ 2729: [HNOI2012]排队 排列组合 + 高精度
Description 某中学有 n 名男同学,m 名女同学和两名老师要排队参加体检.他们排成一条直线,并且任意两名女同学不能相邻,两名老师也不能相邻,那么一共有多少种排法呢?(注意:任意两个人都是不 ...
- 学习日记7、mvc +easyui datagrid excel上传
1.首先获取datagrid所有行的数据 var rows = $("#List").datagrid("getRows"); 2.进行数据转换转化成JSON格 ...
- django搭建一个小型的服务器运维网站-用户登陆与session
目录 项目介绍和源码: 拿来即用的bootstrap模板: 服务器SSH服务配置与python中paramiko的使用: 用户登陆与session; 最简单的实践之修改服务器时间: 查看和修改服务器配 ...
- docker 部署ftp
1.搜索ftp镜像 docker search vsftpd 2.拉取ftp镜像 docker pull fauria/vsftpd 3.启动ftpdocker docker run -d -v /h ...
- delphi 获取文件的最新修改时间 http://www.delphitop.com/html/wenjian/64.html
delphi 获取文件的最新修改时间 作者:admin 来源:未知 日期:2010/1/28 13:15:22 人气:1054 标签: QQ空间新浪微博腾讯微博腾讯朋友QQ收藏百度空间百度贴吧更多0 ...
- 为什么有mac地址还学要有IP地址??
历史原因:早期的以太网只有集线器 ,没有交换机,所以发出去的包能被以太网内的所有机器监听到,因此要附带上MAC地址,每个机器只需要接受与自己MAC地址相匹配的包. 个人感觉上面的说法并不是太准确.找明 ...