令牌桶算法Java实现
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051/** * 令牌桶,使用令牌桶算法进行限流 * */public class TokenBucket { private double capacity;// 令牌容量,桶内能容纳的令牌数 private double rate;// 令牌增加速率,每毫秒增加的可用令牌数 private double lastSize;// 上次获得令牌之后,桶内的剩余可用令牌数 private long lastAcquireTime;// 上次获得令牌的时间 /** * @param capacity 令牌容量,桶内能容纳的令牌数 * @param rate 令牌增加速率,每毫秒增加的可用令牌数 */ public TokenBucket(double capacity, double rate) { this.capacity = capacity; this.rate = ...
Spring注解开发
Spring注解开发
@Configuration 用于标注配置类
@Bean 结合@Configuration(full mode)使用或结合@Component(light mode)使用。可以导入第三方组件,入方法有参数默认从IOC容器中获取,可以指定initMethod和destroyMethod 指定初始化和销毁方法,多实例对象不会调用销毁方法.
包扫描@ComponentScan (@ComponentScans可以配置多个扫描,@TypeFilter:指定过滤规则,自己实现TypeFilter类)组件(@Service、@Controller、@Repository):包扫描+组件注解导入注解。
@Scope:设置组件作用域 1.prototype:多例的2.singleton:单例的(默认值)
@Lazy 懒加载
@Conditional({Condition}):按照一定的条件进行判断,满足条件给容器中注册Bean,传入Condition数组,,使用时需自己创建类继承Condition然后重写match方法。
@Import[快速给容器中导入一个组件]
Import( ...
Redis面试
概述什么是Redis?Redis 是一个使用 C 语言写成的,开源的高性能key-value非关系缓存数据库。它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型)。Redis的数据都基于缓存的,所以很快,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。Redis也可以实现数据写入磁盘中,保证了数据的安全不丢失,而且Redis的操作是原子性的。
Redis的优点?优点
读写性能优异, Redis能读的速度是110000次/s,写的速度是81000次/s。
支持数据持久化,支持AOF和RDB两种持久化方式。
支持事务,Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。
数据结构丰富,除了支持string类型的value外还支持hash、set、zset、list等数据结构。
支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
缺点
数据库容量受到物理内存的限制,不能用作海量数据的高性能 ...
深度探索MySQL主从复制原理
概要MySQL Replication (MySQL 主从复制) 是什么?为什么要主从复制以及它的实现原理是什么?
MySQL 主从复制概念
MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,从节点可以复制主数据库中的所有数据库或者特定的数据库,或者特定的表。
MySQL 主从复制主要用途
l 读写分离 在开发工作中,有时候会遇见某个sql 语句需要锁表,导致暂时不能使用读的服务,这样就会影响现有业务,使用主从复制,让主库负责写,从库负责读,这样,即使主库出现了锁表的情景,通过读从库也可以保证业务的正常运作。 l 数据实时备份,当系统中某个节点发生故障时,可以方便的故障切换 l 高可用HA l 架构扩展 随着系统中业务访问量的增大,如果是单机部署数据库,就会导致I/O访问频率过高。有了主从复制,增加多个数据存储节点,将负载分布在多个从节点上,降低单机磁盘I/O访问的频率,提高单个机器的I/O性能。 ...
性能对比:ReentrantLock vs Synchronized
性能对比:ReentrantLock vs Synchronized起因最近遇到高并发引起的性能问题,最终定位到的问题是 LinkedBlockingQueue 的性能不行,最终通过创建了多个 Queue 来减少每个 Queue 的竞争压力。人生中第一次遇到 JDK 自带数据结构无法满足需求的情形,决心好好研究一下为什么。
压测在一个 40 个核的机器上,tomcat 默认 200 个线程,发送方以 500 并发约 1w QPS 发送请求,要求999 分位的响应在 50ms 左右。代码中有一个异步写入数据库的任务,实际测试时有超过 60% 的延时都在写入队列中(实际上是往 ThreadPool 提交任务)。于是开始调研 LinkedBlockingQueue 的实现。
LinkedBlockingQueue 相当于是普通 LinkedList 加上 ReentrantLock 在操作时加锁。而 ReentrantLock (以及其它 Java 中的锁)内部都是靠 CAS 来实现原子性。而 CAS 在高并发时因为线程会不停重试,所以理论上性能会比原生的锁更差。
测试与结果实际上想对比 C ...
零拷贝原理
数据拷贝传统IO传统的一次IO流程
read: 数据从磁盘读取到内核缓冲区, 然后从内核缓冲区拷贝到用户缓冲区
write: 数据从用户缓冲区写入socket缓冲区, 然后写入网卡设备
read之后, 也即向操作系统发出IO调用, 用户态切换到内核态
DMA拷贝数据从硬盘到内核缓冲区
CPU拷贝内核缓冲区数据到用户缓冲区, 内核态切换到用户态
write之后, 也即发起IO调用, 用户态切换到内核态
CPU拷贝用户缓冲区数据到socket缓冲区
DMA拷贝socket缓冲区到网卡设备, 内核态切换到用户态
上述过程可以看出有4次上下文切换, 4次拷贝. 其实这个地方可以优化, 我们把数据拷贝到用户缓冲区再从用户缓冲区拿出数据到socket纯属多此一举, 如果有一种操作直接可以把数据从内核缓冲区到socket缓冲区的话, 就能减少拷贝操作了
零拷贝mmp优化mmp优化是基于虚拟内存实现的
虚拟内存是什么东西?简单来讲, 虚拟内存是由于主存不够大而出现的辅存(理论上来说, 主存想多大就多大, 实际上来说怎么可能, 主存越大价格越高, 追求性价比的情况下才出现的虚拟内存)
虚拟 ...
硬件层面CAS又是如何保证原子性
硬件层面CAS又是如何保证原子性的呢? 真的完全没加锁吗?
拿比较常见的x86架构的CPU来说,其实 CAS 操作通常使用 cmpxchg 指令实现的。
可是为啥cmpxchg 指令能保证原子性呢? 主要是有以下几个方面的保障:
1.cmpxchg 指令是一条原子指令。在 CPU 执行cmpxchg 指令时,处理器会自动锁定总线,防止其他 CPU 访问共享变量,然后执行比较和交换操作,最后释放总线。
2.cmpxchg 指令在执行期间,CPU 会自动禁止中断。这样可以确保 CAS 操作的原子性,避免中新或其他干扰对操作的影响。
3.cmpxchg 指令是硬件实现的,可以保证其原子性和正确性。CPU 中的硬件电路确保了cmpxchg 指令的正确执行,以及对共享变量的访问是原子的。
所以,在操作系统层面,CAS还是会加锁的,通过加锁的方式锁定总线,避免其他CPU访问共享变量。所以,解决并发问题,归根结底还得靠锁!!!
synchronized优化
概述synchronized能够实现线程同步。无论怎么使用,最终都是对对象加锁。
锁class对象、静态方法 都是锁类对象
锁普通对象、普通方法,都是锁实例对象
为什么synchronized最终都是作用在对象上呢? 因为对象在堆中除了除了有字段属性外,还有固定的对象头,通过对象头最终可以得知这个对象是否被加过锁,以及持有锁的线程是谁。(第2节 对象结构)
仔细研究对象头后,发现其中记录了多种锁的状态。锁的升级与其息息相关。(第3节 锁优化策略)
许多线程长时间阻塞,说明锁已经升级到了重量级锁,JVM使用Monitor处理阻塞线程,如wait、notify等。(第1节 Monitor阻塞机制)
AQS也是参照jvm底层Monitor处理方式实现的,但是性能上更优一些。(第4节 与AQS的对比)
一、理解synchronized是非公平、可重入、独占锁
wait和notify使用时线程必须持有锁
synchronized对MESA管程模型的实现
底层逻辑:
cxq、EntryList都是先进后出队列FILO
争抢锁失败的线程会进入cxq
获取锁的线程调用wait后进入waitSe ...
Synchronized与@Transactional同时使用的问题
Synchronized与@Transactional同时使用的问题@Transactional注解实现事务的功能是通过aop的方式实现的,在Synchronized锁生效之前就开启了事务,然后锁关闭,最后再提交事务,在高并发的情况下,存在同步锁关闭,但是事务还未提交,新的线程已经重新获取了同步锁,数据库数据此时还未更新,新线程读到的数据是旧数据。导致Synchronized同步不生效问题
解决方法:
需要在事务开启之前开启同步锁。可以将Synchronized放置在调用事务函数之前。
使用ShardingJdbc实现Mysql数据库主从复制
SQL标准中定义了4种隔离级别,分别是读未提交、读已提交、可重复读以及序列化。不同的隔离级别下,可以解决不同的并发问题,如下图所示。当然MySQL也基本遵循了这个标准,但是在实现上稍有不同。
本文重点探讨下MySQL是如何解决幻读问题的,首先串行化隔离级别铁定是可以解决所有的并发问题,相当于每个事务按顺序执行,但是性能很差,不是本文重点讨论对象。实际上MySQL默认的事务隔离级别是可重复读,难道这种隔离级别下MySQL就不管幻读问题了吗?其实不是的,本文就带大家一起看看MySQL在可重复读隔离级别下是如何解决幻读问题的。
什么是幻读?幻读是指一个事务中按照某个条件先后两次读取数据库,两次读取结果的条数不同,更加强调的是读到了之前没有读到的数据,这种现象称为幻读。
举个例子:
事务A一开始只读取到‘张三’的数据记录。然后另外一个事务B插入了‘赵六’的数据记录。事务A再次读取,发现了‘张三’、‘赵六’两条数据,明明同一个事务,同样的查询条件,前后两次读取,多了一条记录,相当于“幻影”,这种情况就是幻读。
什么是普通读和当前读?其实读这个操作也有两种情况,一种是普通读,就像上面例子的那样 ...









