CAS

redis限流的3种实现方式

送分小仙女□ 提交于 2020-08-09 18:59:46
Redis限流的实现方式有3种,分别是:1、基于Redis的setnx的操作,给指定的key设置了过期实践;2、基于Redis的数据结构zset,将请求打造成一个zset数组;3、基于Redis的令牌桶算法,输出速率大于输入速率,就要限流。 第一种:基于Redis的setnx的操作 我们在使用Redis的分布式锁的时候,大家都知道是依靠了setnx的指令,在CAS(Compare and swap)的操作的时候,同时给指定的key设置了过期实践(expire),我们在限流的主要目的就是为了在单位时间内,有且仅有N数量的请求能够访问我的代码程序。所以依靠setnx可以很轻松的做到这方面的功能。 比如我们需要在10秒内限定20个请求,那么我们在setnx的时候可以设置过期时间10,当请求的setnx数量达到20时候即达到了限流效果。代码比较简单就不做展示了。 当然这种做法的弊端是很多的,比如当统计1-10秒的时候,无法统计2-11秒之内,如果需要统计N秒内的M个请求,那么我们的Redis中需要保持N个key等等问题 第二种:基于Redis的数据结构zset 其实限流涉及的最主要的就是滑动窗口,上面也提到1-10怎么变成2-11。其实也就是起始值和末端值都各+1即可。 而我们如果用Redis的list数据结构可以轻而易举的实现该功能 我们可以将请求打造成一个zset数组

JAVA并发编程入门篇,思考同步锁Synchronized背后的实现哲学

时光怂恿深爱的人放手 提交于 2020-08-09 18:11:10
多线程在概念上类似抢占式多任务处理,线程的合理使用能够提升程序的处理能力,但是使用的同时也带来了弊端,对于共享变量访问就会产生安全性的问题。下面来看一个多线程访问共享变量的例子: public class ThreadSafty { private static int count = 0; public static void incr() { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } count ++; } public static void main(String[] args) throws InterruptedException { for (int i = 0 ; i < 1000; i++) { new Thread(()->{ ThreadSafty.incr(); },"threadSafty" + i).start(); } TimeUnit.SECONDS.sleep(3); System.out.println("运行结果是:" + count); } } 变量count的运行结果始终是小于等于1000的随机数,因为线程的可见性和原子性。 一、多线程访问的数据安全性 如何保证线程并行运行的数据安全性问题,这里首先能够想到的是加锁吧

面试处处都是坑啊?让实现线程安全的单例,又不让用synchronized

南楼画角 提交于 2020-08-09 18:01:50
单例模式,是Java中比较常见的一个设计模式,也是我在面试时经常会问到的一个问题。 经过我的初步统计,基本上有60%左右的人可以说出2-4种单例的实现方式,有40%左右的人可以说出5-6种单例的实现方式,只有20%左右的人能够说出7种单例的实现。 而只有不到1%的人能够说出7种以上的单例实现。 其实,作为面试官,我大多数情况下之所以问单例模式,是因为这个题目可以问到很多知识点。 比如线程安全、类加载机制、synchronized的原理、volatile的原理、指令重排与内存屏障、枚举的实现、反射与单例模式、序列化如何破坏单例、CAS、CAS的ABA问题、Threadlocal等知识。 一般情况下,只需要从单例开始问起,大概就可以完成一场面试的整个流程,把我想问的东西都问完,可以比较全面的了解一个面试者的水平。 以下,是一次面试现场的还原,从单例模式开始: Q:你知道怎么不使用synchronized和lock实现一个线程安全的单例吗? A:我知道,可以使用"静态内部类"实现。 静态内部类实现单例模式: Q:除了静态内部类还会其他的方式吗? A:还有就是两种饿汉模式。 饿汉实现单例模式: 饿汉变种实现单例模式: Q:那你上面提到的几种都是线程安全的吗? A:是线程安全的 Q:那是如何做到线程安全的呢? A:应该是因为我使用了static,然后类加载的时候就线程安全了吧? Q

ReentrantLock解析及源码分析

丶灬走出姿态 提交于 2020-08-09 15:11:20
本文结构 Tips:说明一部分概念及阅读源码需要的基础内容 ReentrantLock简介 公平机制:对于公平机制和非公平机制进行介绍,包含对比 实现: Sync 源码解析额,公平和非公平模式的加锁、解锁过程及源码分析 公平锁和非公平锁的加锁流程图 ReentrantLock 提供的一些其他方法 Condition :这里只是一提,不会有什么有意义的内容 ReentrantLock 全部源码理解:个人阅读 ReentrantLock 源码的时候做的注释,需要结合 AQS 一块理解 Tips: 同步等待队列:即普遍的资料中提到的同步队列,由 AQS 维护。在代码的英文注释中写道wait queue,因此我在这里翻译成同步等待队列 条件等待队列:即普遍的资料中提到的等待队列,由 AQS.Condition 维护,在代码的英文注释中也是写道 wait queue ,因此我在这里翻译成条件等待队列 本篇文章会大量提到 AQS 这个类,并且大量的方法都在 AQS 中实现,本文对会对使用到的方法进行解释,但是对于 AQS 内部的属性没有过多解释,后续篇章写 AQS 会专门写,建议可以了解一下,有助于理解 建议阅读前先了解 AQS 中的 Node 类,有助于阅读,本文不会说明 ReentrantLock简介 在多线程编程中,同步和互斥是一个非常重要的问题。 在java中可以通过使用

Synchronized关键字与ReetrantLock同步锁学习笔记

淺唱寂寞╮ 提交于 2020-08-09 12:17:07
一、Synchronized 1、概念 synchronized保证被修饰的方法或代码块操作的原子性、可见性和有序性。synchronized可重入锁、不可中断,适合线程竞争不激烈。 被Synchronized 关键字描述的方法或代码块在多线程环境下同一时间只能由一个线程进行访问,因为在持有当前锁的线程执行完成之前,其他线程想要调用相关方法就必须进行排队,直到当前线程执行完成才释放锁给其他线程,所以保证了原子性。 被Synchronized 关键字描述的方法或代码块在多线程环境下数据是同步的,即当获取到锁后先将内存复制到自己的缓存中操作,释放锁之前会把缓存中的数据复制到共享内存中,所以保证了可见性。 被Synchronized 关键字描述的方法或代码块在多线程环境下同一时间只能由一个线程访问,代码内部是有序的,不会出发JMM指令重排机制,所以保证了有序性。 在使用Sychronized关键字时需要把握如下注意点: 一把锁只能同时被一个线程获取,没有获得锁的线程只能等待; 每个实例都对应有自己的一把锁(this),不同实例之间互不影响;例外:锁对象是*.class以及synchronized修饰的是static方法的时候,所有对象公用同一把锁 synchronized修饰的方法,无论方法正常执行完毕还是抛出异常,都会释放锁 2、对象锁 包括方法锁(默认锁对象为this,当前实例对象

DDR2(4):对DDR2 IP再次封装

蹲街弑〆低调 提交于 2020-08-09 12:05:48
  生成 DDR2 IP 后就可以使用了,网络上也很多直接对 DDR2 IP 操作的例程,但其实这样还不够好,我们可以对这个 DDR2 IP 进行再次封装,让它变得更加好用。现在试着封装一下,之前的 DDR2 IP 名字就是 DDR2.v,这个封装就命名为 DDR2_burst,其主要作用是完成一次 DDR2 的突发读写,即外界可以任意设置突发长度,在这个模块将这个任意的突发长度转换为突发长度 4 写进 DDR2 IP 里。   封装 DDR2 IP 有常见的两种方式,一种是设计 DDR2_burst 和 DDR2 IP 外部互联,再用第三个 .v 文件将这两者连线,如下所示:   另一种是直接将 DDR2_IP 放到 DDR2_burst 代码里面例化,如下所示:   显然,第二种比较简洁,文件较少。 一、参数集 DDR2_param   先给出参数集,方便移植。命名为 DDR2_param.v,内容如下: // ************************************************************************** // *** 名称 : DDR2_param.v // *** 作者 : xianyu_FPGA // *** 博客 : https://www.cnblogs.com/xianyufpga/ // *** 日期 :

同步工具——Exchanger

只谈情不闲聊 提交于 2020-08-09 10:55:45
本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。 并发编程系列博客传送门 本文是转载问斩,原文请见 这里 一、Exchanger简介 Exchanger——交换器,是JDK1.5时引入的一个同步器,从字面上就可以看出,这个类的主要作用是交换数据。 Exchanger有点类似于 CyclicBarrier ,我们知道CyclicBarrier是一个栅栏,到达栅栏的线程需要等待其它一定数量的线程到达后,才能通过栅栏。 Exchanger可以看成是一个双向栅栏,如下图: Thread1线程到达栅栏后,会首先观察有没其它线程已经到达栅栏,如果没有就会等待,如果已经有其它线程(Thread2)已经到达了,就会以成对的方式交换各自携带的信息,因此Exchanger非常适合用于两个线程之间的数据交换。 二、Exchanger示例 我们来看一个示例,理解下Exchanger的功能: 示例: 假设现在有1个生产者,1个消费者,如果要实现生产者-消费者模式,一般的思路是利用队列作为一个消息队列,生产者不断生产消息,然后入队;消费者不断从消息队列中取消息进行消费。如果队列满了,生产者等待,如果队列空了,消费者等待。 我们来看下如何利用 Exchanger 实现生产者-消息者模式: 生产者: public class Producer

从锁升级的角度理解synchronized

若如初见. 提交于 2020-08-09 10:49:51
前言 在 Java 中为保证线程安全,可以使用关键字 synchronized 保护代码,在多个线程之间同时只能有一个线程执行被保护的代码。 synchronized 锁的到底是什么?是对象,还是代码块呢? 保证线程安全已经有了 synchronized 为什么又会出现 Lock 呢,二者之间有什么区别呢? synchronized 一定比 Lock 性能差吗? synchronized 的锁升级过程是什么,偏向锁,轻量级锁,自旋锁,重量级锁怎么一步一步实现的? synchronized 使用 1、用在静态方法 public class SimpleUserSync { public static int a = 0; // 相当于 synchronized (SimpleUserSync.class){a++;} public synchronized static void addA_1() { a++; } } 2、用在成员方法上 public class SimpleUserSync { public static int a = 0; // 相当于 synchronized (this){a++;} public synchronized void addA_1() { a++; } } 3、用在代码块 private static final Object LOCK

JUC整理笔记一之细说Unsafe

☆樱花仙子☆ 提交于 2020-08-09 08:16:25
JUC(java.util.concurrent)的开始,可以说是从Unsafe类开始。 Unsafe 简介 Unsafe在 sun.misc 下,顾名思义,这是一个不安全的类,因为Unsafe类所操作的并不属于Java标准,Java的一系列内存操作都是交给jvm的,而Unsafe类却能有像C语言的指针一样直接操作内存的能力,同时也会带来了指针的问题。过度使用Unsafe类的话,会使出错率变得更大,因此官方才命名为Unsafe,并且不建议使用,连注释的没有。 而为了安全使用Unsafe,Unsafe类只允许jdk自带的类使用,从下面的代码中可以看出 public static Unsafe getUnsafe() { Class<?> caller = Reflection.getCallerClass(); if (!VM.isSystemDomainLoader(caller.getClassLoader())) throw new SecurityException("Unsafe"); return theUnsafe; } 如果当前Class是非系统加载的(也就是caller.getClassLoader()不为空),直接抛出 SecurityException 。 在java9之后,又出现了一个 jdk.internal.misc.Unsafe 类,其功能与 sun

mysql事物默认隔离级别下乐观锁(CAS)重试数据版本不更新的问题

Deadly 提交于 2020-08-09 08:05:03
异常信息 Ccom.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction 问题发生原因 乐观锁修改数据的时候, 数据版本号(version)已经被修改了,导致修改失败. 进行重试修改时, 每次从数据库读取出来的数据不是数据库最新版本, 导致无限次重试, 直到该事物超时自动退出 使用乐观锁(CAS)机制去更新一条记录, 从数据库查询一条数据, 当查出来数据版本号是1, 在修改数据的时候, 把数据版本号作为修改条件之一,​update `table_name` set version=`2` where version=`1`​ , 如果修改失败, 那么该数据已经被更新过了, 重新读取数据, 进行重试, 而Mysql数据库中, 开启事物之后, 在当前事物中, 多次查询的值, 会是同一个, 即修改失败, 进行重新读数据, 得到的数据版本号是该次事物中第一次读的时候的版本号 (即数据库事物隔离级别中的可重复读, 避免脏读现象(多次读取值不一致), 类似于开启一个事物的时候, 每次读取, 会把查询的数据复制到事物空间, 当前事物读数据库的时候, 不会读表中的实际数据, 而是读事物空间的数据. 因为这个原因,