/**
* @description 队列同步器,利用原子整形模仿AQS,非公平锁(简单自适应自旋)
* @since 2020/2/4
*/
public class QueueSynchronizer { private AtomicInteger state=new AtomicInteger(0);//0为可用,1为被用,2为已经重入一次,依此
private Thread onwThread;
private ConcurrentLinkedQueue<Thread> concurrentLinkedQueue=new ConcurrentLinkedQueue();//阻塞队列
//AQS队列中的头的thread永远为null,这里与AQS不一致,ConcurrentLinkedQueue不允许空值 //线程私有变量
private ThreadLocal<Integer> spinCount=new ThreadLocal<Integer>();//线程竞争失败后的自旋次数
private ThreadLocal<Integer> spinIncrement=new ThreadLocal<Integer>();//自旋成功后的自旋增量
private ThreadLocal<Integer> spinDecrement=new ThreadLocal<Integer>();//自旋成功后的自旋减量
private int sc;
private int si;
private int sd; //指定默认的自旋次数,成功增量,失败减量
public QueueSynchronizer(){
sc=4000;
si=900;
sd=700;
} //指定初始的自旋次数,成功增量,失败减量
public QueueSynchronizer(int spinCount, int spinIncrement, int spinDecrement){
sc=spinCount;
si=spinIncrement;
sd=spinDecrement;
} /**
* @description: 获取锁,有以下情况:(非公共平模式,不判断队伍存在与否)
* 1.当前锁为自由状态,如果cas成功,那么线程成功持有,否则失败
* 2.当前锁被人持有,如果持有人正是当前线程,那么获取成功,线程重入,否则失败
* @param
* @return: boolean 获取成功为true,失败为false
* @date: 2020/2/5
*/
public boolean aquire(){
if(state.get()==0){//这里不直接使用cas,是为了减少cas的调用,因为这是一条cpu指令,耗费资源较大(能省则省)
if(state.compareAndSet(0,1)) {
onwThread=Thread.currentThread();
return true;
}else return false;
}else if(onwThread==Thread.currentThread()) {
state.incrementAndGet();//重入
return true;
}else return false;
} /**
* @description: 自旋,如果成功,那么设置当前线程,增加下次自旋次数,否则减少下次自旋次数
* @param
* @return: boolean 自旋成功为true,失败为false
* @date: 2020/2/5
*/
public boolean spin(){
int temp=spinCount.get();//缓存本次自旋次数
while(temp>0) {
temp--;
if(state.compareAndSet(0,1)) {//自旋成功,设置当前线程,增加下次自旋次数
onwThread=Thread.currentThread();
spinCount.set(spinCount.get()+spinIncrement.get());
return true;
}
}
spinCount.set(Math.max(spinCount.get()-spinDecrement.get(),0));//自旋失败,减少下次自旋次数。
return false;
} /**
* @description: 并发入队,在入队前做最后一次询问,若成功入队,线程设置中断后,park,
* 醒来之后中断取反,再去尝试获取锁
* @param
* @return: void
* @date: 2020/2/5
*/
public void inQueue(){
if(!aquire()){//入队前的最后一次询问
concurrentLinkedQueue.add(Thread.currentThread());
System.out.println(Thread.currentThread().getName()+"入队等候");
Thread.currentThread().interrupt();//设置中断
LockSupport.park();
System.out.println(Thread.currentThread().getName()+"被唤醒");
Thread.currentThread().interrupt();//再次中断取反
tryAcquire();//醒来之后再去尝试
}else System.out.println(Thread.currentThread().getName()+"入队前最后一次获取成功");
} /**
* @description: state-1,如果此时state=0而且队列不为空,则唤醒队头,让其重新竞争
* @param
* @return: void
* @date: 2020/2/5
*/
public void release() throws RuntimeException{
if(onwThread==Thread.currentThread()) {
//这里先减-1再去唤醒,此时若有新线程进来则刚好非公平地获取到
if(state.decrementAndGet()==0&&!concurrentLinkedQueue.isEmpty()) {
Thread thread=concurrentLinkedQueue.poll();
LockSupport.unpark(thread);
}
if(state.get()==0) System.out.println(Thread.currentThread().getName()+"释放了锁");
else System.out.println(Thread.currentThread().getName()+"还要释放了"+state.get()+"次");
}
else throw new RuntimeException("非法释放,当前线程并非锁的拥有者!");
} /**
* @description: 线程首次Lock前调用,初始化个线程的自旋次数,增量,减量
* @param
* @return: void
* @date: 2020/2/5
*/
public void init(){
this.spinCount.set(sc);
this.spinIncrement.set(si);
this.spinDecrement.set(sd);
} /**
* @description: 尝试获取锁,失败后尝试自旋获取,若仍然失败则进入阻塞队列,park,等待别人用完后来unpark,
* 然后再次尝试获取锁。
* @param
* @return: void
* @date: 2020/2/5
*/
public void tryAcquire(){
//if(!aquire()&&!spin()) inQueue();
if(aquire()) {
if(state.get()==1) System.out.println(Thread.currentThread().getName()+"获取成功");
else System.out.println(Thread.currentThread().getName()+"获取成功,重入了"+(state.get()-1)+"次");
}
else{
System.out.println(Thread.currentThread().getName()+"获取失败,自旋"+spinCount.get()+"次");
if(spinCount.get()>0&&spin()) System.out.println(Thread.currentThread().getName()+"自旋成功");
else{
System.out.println(Thread.currentThread().getName()+"自旋失败,尝试进入队列");
inQueue();
}
}
} }
public class MyLock implements Lock{
private QueueSynchronizer queueSynchronizer =new QueueSynchronizer(); public void init() { queueSynchronizer.init();} @Override
public void lock() {
queueSynchronizer.tryAcquire();
} @Override
public void unlock() {
queueSynchronizer.release();
}
}
public interface Lock {
void lock();
void unlock();
}
public class MyLockTest {
private static int sum=100;
static MyLock myLock = new MyLock();
public static void main(String[] args) {
for (int j = 0; j < 10; j++) {
new Thread(()->{
myLock.init();//各线程初次使用时先初始化
myLock.lock();
myLock.lock();
for (int i = 0; i < 10; i++) {
System.out.println(--sum+" "+Thread.currentThread().getName()+"one");
}
myLock.unlock(); for (int i = 0; i < 10; i++) {
System.out.println(--sum+" "+Thread.currentThread().getName()+"two");
}
myLock.unlock();
}).start();
} }
}

利用Atomic, ThreadLocal, 模仿AQS, ReentrantLock的更多相关文章

  1. paip.提升性能----java 无锁结构(CAS, Atomic, Threadlocal, volatile, 函数式编码, 不变对象)

    paip.提升性能----java 无锁结构(CAS, Atomic, Threadlocal, volatile, 函数式编码, 不变对象) 1     锁的缺点 2     CAS(Compare ...

  2. JUC AQS ReentrantLock源码分析

    警告⚠️:本文耗时很长,先做好心理准备,建议PC端浏览器浏览效果更佳. Java的内置锁一直都是备受争议的,在JDK1.6之前,synchronized这个重量级锁其性能一直都是较为低下,虽然在1.6 ...

  3. 技本功丨利用 Atomic 构建 React 项目工作流,so easy!

    近日刷微博,#2018年结婚率创新低#荣登热门话题NO.1,沪浙最不积极. 生活压力越大,缺爱的人也越来越多...据本萌的不完全观察,程序猿虽然是压力加成的职业,在袋鼠云还是有不少早早脱了单.至于,脱 ...

  4. 利用art.template模仿VUE 一次渲染多个模版

    TypeScript代码 import template = require('art-template/lib/template-web'); interface TemplateBindConfi ...

  5. 利用art.template模仿VUE

    首先先看一下Typescript代码: import template = require('art-template/lib/template-web'); interface TemplateBi ...

  6. 扒一扒ReentrantLock以及AQS实现原理

    提到JAVA加锁,我们通常会想到synchronized关键字或者是Java Concurrent Util(后面简称JCU)包下面的Lock,今天就来扒一扒Lock是如何实现的,比如我们可以先提出一 ...

  7. 深圳某小公司面试题:AQS是什么?公平锁和非公平锁?ReentrantLock?

    AQS总体来说没有想象中那么难,只要了解它的实现框架,那理解起来就不是什么问题了. AQS在Java还是占很重要的地位的,面试也是经常会问. 目前已经连载11篇啦!进度是一周更新两篇,欢迎持续关注 [ ...

  8. ReentrantLock 实现原理

    使用 synchronize 来做同步处理时,锁的获取和释放都是隐式的,实现的原理是通过编译后加上不同的机器指令来实现. 而 ReentrantLock 就是一个普通的类,它是基于 AQS(Abstr ...

  9. JAVA并发-同步器AQS

    什么是AQS aqs全称为AbstractQueuedSynchronizer,它提供了一个FIFO队列,可以看成是一个用来实现同步锁以及其他涉及到同步功能的核心组件,常见的有:ReentrantLo ...

随机推荐

  1. 「Vijos 1283」「OIBH杯NOIP2006第二次模拟赛」佳佳的魔杖

    佳佳的魔杖 背景 配制成功了珍贵的0号药水,MM的病治好了.轻松下来的佳佳意外的得到了一个好东西--那就是--一种非常珍贵的树枝.这些树枝可以用来做优质的魔杖!当然了,不能只做自己的,至少还要考虑到M ...

  2. CAP 3.0 版本发布通告

    前言 大家好,我们很高兴宣布 CAP 发布了 3.0 版本正式版. 自从上次 CAP 2.6 版本发布 以来,已经过去了几个月的时间,关注的朋友可能知道,在这几个月的时间里,也发布了几个预览版的 3. ...

  3. 【接口测试】使用httpClient获取cookies+携带获取的cookies访问get接口

    数据准备 在本机或者远端机器安装部署moco-runner(参考:https://blog.csdn.net/qq_32706349/article/details/80472445) 这里我们只需要 ...

  4. Sorted 内置函数的排序使用

    Sorted 内置函数的排序使用 Sorted 排序列表 1.倒序对列表进行排序 # 对列表进行降序序排序 list = [1,3,4,23,6,7] list = sorted(list,rever ...

  5. 【python小随笔】python 解析xml数据的新手大坑>>抓取多重标签,遍历各标签的数据

    xml文档: <GetMatchingProductResult ASIN="B071LF9R6G" status="Success">...< ...

  6. Collections 工具类

    针对 List 集合的方法 排序 sort 如果集合元素为基本数据类型,采用快排:对于集合元素为引用类型,采用归并排序. //对指定 List 集合的元素按照自然排序 void sort(List&l ...

  7. 《C++Primer》第五版习题详细答案--目录

    作者:cosefy ps: 答案是个人学习过程的记录,仅作参考. <C++Primer>第五版习题答案目录 第一章:引用 第二章:变量和基本类型 第三章:字符串,向量和数组 第四章:表达式

  8. C#反射与特性(六):设计一个仿ASP.NETCore依赖注入Web

    目录 1,编写依赖注入框架 1.1 路由索引 1.2 依赖实例化 1.3 实例化类型.依赖注入.调用方法 2,编写控制器和参数类型 2.1 编写类型 2.2 实现控制器 3,实现低配山寨 ASP.NE ...

  9. DHCP服务器搭建

    一.服务端安装配置 1.安装dhcp相关软件包 执行命令:yum install dhcp dhcp-devel -y #通过yum安装dhcp软件包 2.编辑配置dhcp的配置文件,文件路径:/et ...

  10. DSN

    用户DSN注册信息记录在本机的注册表上 文件DSN保存在本地磁盘上 系统DSN注册在服务器的注册表上,所以客户端连接服务器,只要一台在服务器建立了DSN,其他客户端登录时都会看到该DSN