自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(33)
  • 收藏
  • 关注

原创 来看看缓存

什么是缓存?缓存时对原始数据的一个复制的副本,我们一般将数据缓存起来以便于备用,常常用来加速读取缓存有什么用?用来提升读取的速度,优化系统的吞吐量以我们的java和mysql之间进行交互为例子,我们从mysql中读取数据,需要进行IO,如果忽略mysql自己的Buffer pool中的缓存,把mysql的每次读取都看成一次IO,那么当我们多次查询同一个数据的时候,需要进行N次IO,IO性能有限,所以我们引入本地缓存或者分布式缓存,不再从磁盘上去进行IO,而是从内存中读取,内存读取比IO普遍要快,对于

2022-02-19 21:31:49 543 1

转载 动态线程池

动态线程池1.1 线程池是什么线程池(Thread Pool)是一种基于池化思想管理线程的工具,经常出现在多线程服务器中,如MySQL。线程过多会带来额外的开销,其中包括创建销毁线程的开销、调度线程的开销等等,同时也降低了计算机的整体性能。线程池维护多个线程,等待监督管理者分配可并发执行的任务。这种做法,一方面避免了处理任务时创建销毁线程开销的代价,另一方面避免了线程数量膨胀导致的过分调度问题,保证了对内核的充分利用。而本文描述线程池是JDK中提供的ThreadPoolExecutor类。当然,使

2022-02-08 14:47:11 2311

翻译 大型电商网站设计——商品详情页面静态化

分布式系统的cap理论首先把分布式系统中的三个特性进行了如下归纳:1.一致性© : 在分布式系统中的所有数据备份,在同一时刻是否是同样的值(等同于所有节点访问同一份最新的数据副本)2.可用性(A) : 在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求(对数据更新具备高可用性)3.分区容错§ : 以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。应用数据静态化架构高性能单页web应用在电商网站

2022-02-27 22:30:32 2012

原创 Redis设计与实现(十)—— 哨兵

哨兵的核心功能是主节点的自动故障转移监控:哨兵会不断地检查主节点和从节点是否运作正常。自动故障转移:当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中 一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。配置提供者:客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址。通知:哨兵可以将故障转移的结果发送给客户端。在我们的哨兵架构中,主要会有两种节点组成:哨兵节点和数据节点:哨兵节点:哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的redis节

2022-02-23 11:03:06 477

原创 Redis设计与实现(九)—— 主从复制

主从复制是值将一台Redis的数据,复制到另一台从节点上,数据的复制是单向的,只能由主节点到从节点主从复制的作用:- 数据冗余:主从复制实现数据的热备,是除了持久化之外的一种数据冗余方式- 故障恢复:当主节点出现问题后,从节点可以提供服务,实现快速恢复- 负载均衡:在主从复制的基础上,可以配合读写分离,然后可以由主节点提供写,从节点读,分担负载- 高可用基石:集群等的基石...

2022-02-21 18:14:10 230

原创 Redis设计与实现(八)—— 持久化

为什么需要持久化?因为Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘;当下次Redis重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置。Redis分为两种持久化机制,RDB和AOFRDB将当前数据快照保存到硬盘,AOF则是将每次执行的写命令保存到硬盘(类似于MySQL的binlog);由于AOF持久化的实时性更好,即当进程意外退出时丢失的数据更少,因

2022-02-21 17:20:28 156

原创 Redis设计与实现(七)—— 压缩列表

压缩列表是 Redis 为了节约内存而开发的, 由一系列特殊编码的连续内存块组成的顺序型(sequential)数据结构。一个压缩列表可以包含任意多个节点(entry), 每个节点可以保存一个字节数组或者一个整数值。如图所示压缩列表构成zlbytes:长度是4字节,用于记录整个压缩链表占用的内存字节数,在对压缩列表进行内存重分配, 或者计算 zlend 的位置时使用。zltail:长度是4字节,记录压缩列表表尾节点距离压缩列表的起始地址有多少字节,根据这个偏移量,程序可以不用遍历就能确定表尾节点的

2022-02-21 16:01:38 485

原创 Redis设计与实现(六)—— 跳表

跳表是一个空间换时间的一个结构,他会增加很多指针,利用指针来快速定位,解决了链表查询时间是O(N)的难题,跳表平均的查询时O(logN),最坏是O(N),N是跳表的长度,我们来看看他的实现我们可以看到我们的跳表的整体实现结构,最左边的是zskiplist,包含了以下属性head:指向跳表的头节点tail:指向跳表的尾节点level:记录跳表中最大层数length:跳表的长度typedef struct zskiplist { // 表头节点和表尾节点 struct zsk

2022-02-21 15:33:38 595

原创 常见灾备技术

一、系统可用性要想理解异地多活,我们需要从架构设计的原则说起。现如今,我们开发一个软件系统,对其要求越来越高,如果你了解一些「架构设计」的要求,就知道一个好的软件架构应该遵循以下 3 个原则:高性能高可用易扩展其中,高性能意味着系统拥有更大流量的处理能力,更低的响应延迟。例如 1 秒可处理 10W 并发请求,接口响应时间 5 ms 等等。易扩展表示系统在迭代新功能时,能以最小的代价去扩展,系统遇到流量压力时,可以在不改动代码的前提下,去扩容系统。而「高可用」这个概念,看起来很抽象,怎么理

2022-02-20 23:29:33 1469

原创 Redis设计与实现(五)—— 哈希表

一、哈希表概述在Redis中,哈希表用的很多,首先是我们的数据库,数据库表采用的就是两张哈希表,用于扩容转化,然后我们的数据类型,像Hash和Set两种类型都有Hash的编码类型,然后接下来说说Hash表二、哈希表结构哈希表typedef struct dictht { // 哈希表数组 dictEntry **table; // 哈希表大小 unsigned long size; // 哈希表大小掩码,用于计算索引值 // 总是等于 size -

2022-02-20 14:00:44 700

原创 Redis设计与实现(四)—— 链表

我们的链表编码在Redis的List中有使用到,学过java或者数据结构的人很容易理解,Redis中就是做的一个双向链表,包含头结点,尾节点,然后有ListNode作为节点的描述LinkedList结构ListNodetypedef struct listNode { // 前置节点 struct listNode *prev; // 后置节点 struct listNode *next; // 节点的值 void *value;} listN

2022-02-20 13:39:13 235

原创 Redis设计与实现(三)—— SDS

一、SDS概述在Redis中,String应该是用的最多的类型了,我们的Key是String类型,由SDS实现,String有SDS,raw,int三种,我们可以把string看成抽象类,然后SDS,raw,int分别是实现类,因为C语言的字符串中有很多使用受限的地方,所以Redis提出了动态字符串SDS二、SDS结构struct sdshdr { // 记录 buf 数组中已使用字节的数量 // 等于 SDS 所保存字符串的长度 int len; // 记录 buf

2022-02-20 13:16:01 291

原创 Redis设计与实现(二)—— RedisObject

一、概述Redis提供了多种基本数据类型和高级的数据类型,然后每种都有多种实现,Redis自己内部会进行判断应该使用哪种编码,当我们的数据放入Redis后,会被包装成RedisObject,然后存入,来看看RedisObject的结构吧二、RedisObject结构当我们执行了set hello world的时候,会产生如下的结构dictEntry:Redis的数据库是一张Hash表,然后里面会包含键值对,可以简单理解为java的HashMap,然后他中间包含了指向Key和Value的指针,以及下

2022-02-20 11:03:55 330

原创 Redis设计与实现(一)——内存模型

一、Redis内存统计Redis是一个基于内存的缓存中间件,所以,我们可能需要去查看Redis的内存使用情况,我们可以使用info命令来查看内存占用info memoryinfo命令可以显示redis服务器的许多信息,包括服务器基本信息、CPU、内存、持久化、客户端连接信息等等;memory是参数,表示只显示内存相关的信息。二、Redis内存划分Redis是一个基于内存的中间件,所以对于我们需要存储的数据,肯定是需要占用内存的,但是Redis是一个进程,是在不断运行的,所以肯定也会有其他需要的内存

2022-02-20 10:48:20 252

原创 多态的原理

首先,在了解多态的原理之前,先了解下面的这些概念来帮助理解方法区:在JVM内存模型中,主要的部分之一,和堆区一样,是线程共享的区域,一般用来存放类信息,常量,静态变量,即时代码编译器编译后的代码...

2022-02-12 15:27:08 594

原创 深入理解JAVA反射

深入理解JAVA反射JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。下面是反射的一段简单的使用public class Relections { public static void main(String[] args) throws Exception { //获取Class的三种方法 //在这里会去利用Clas

2022-02-11 17:35:28 550

原创 Semaphore源码解析

Semaphore源码解析简介Semaphore是常用的同步工具之一,我们设置n,代表同一时间最多只有n个线程在访问这个工具依赖AQS实现,所以在看源码前推荐先去看AQS的介绍,方便理解public class SemaphoneTest { private Semaphore semaphore = new Semaphore(5); private ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 15, 60, TimeUni

2022-02-11 15:24:53 418

原创 阻塞队列(三)—— LinkedBlockingDeque源码

标题LinkedBlockingDeque源码简介LinkedBlockingDeque是一个双端队列,可以消费队头以及队尾的元素,我们可以设定最大容量,但是设定好后不可改变,因为被final修饰了,然后没有设置的话默认是Integer的最大值,只有一把锁和两个条件队列下面来看看源码源码首先是重要内部类 //Node节点 static final class Node<E> { //元素value E item; //前继节点

2022-02-11 14:23:46 446

原创 阻塞队列(二)——LinkedBlockingQueue源码

标题LinkedBlockingQueue源码简介LinkedBlockingQueue是一个基于单向链表实现的阻塞队列,是先进先出的,然后至少包含一个元素,同时不支持null值的元素,持有两把锁,分别用于管控队头出队,队尾入队然后来看他的源码静态内部类 //静态内部类 static class Node<E> { //元素 E item; //下一个Node节点 Node<E> nex

2022-02-11 10:58:21 290

原创 线程池源码解析

线程池源码解析线程池的作用一方面当执行大量异步任务时候线程池能够提供较好的性能,在不使用线程池的时候,每当需要执行异步任务时候是直接 new 一线程进行运行,而线程的创建和销毁是需要开销的。使用线程池时候,线程池里面的线程是可复用的,不会每次执行异步任务时候都重新创建和销毁线程。另一方面线程池提供了一种资源限制和管理的手段,比如可以限制线程的个数,动态新增线程等,每个 ThreadPoolExecutor 也保留了一些基本的统计数据,比如当前线程池完成的任务数目等。ThreadPoolExecuto

2022-02-10 14:53:25 625

原创 CountDownLatch源码解析

CountDownLatch源码解析CountDownLatch 允许一个或多个线程等待其他线程完成操作。使用示例public class CountDownLatchTest { public static void main(String[] args) { final CountDownLatch latch = new CountDownLatch(2); System.out.println("主线程开始执行…… ……"); //第一

2022-02-09 15:49:13 523

原创 Condition源码讲解

Condition是一个等待队列,作用类似与我们Object类中的wait()以及notify()方法,作用都是用于线程的唤醒与等待Condition比我们在Object中的等待队列作用要更强大,更灵活,像我们的ConditionObject可以利用newCondition()来产生多个等待队列下面来介绍Condition的源码与实现首先是接口Condition,它定义了我们的Condition的基本功能public interface Condition { //常用的线程挂起等待的方

2022-02-09 11:32:59 618

原创 阻塞队列(一)—— ArrayBlockingQueue源码解析

ArrayBlockingQueue源码解析ArrayBlockingQueue是一个阻塞队列,阻塞队列差不多就是依靠消费者和生产者模型来实现的,不过是多生产者,多消费者然后ArrayBlockingQueue的特点如下:1、只有1把锁,所以不能同时的进行入队和出队的操作,2、基于数组实现,同时是一个队列,所以会有两个下标分别用来记录下一个插入点和下一个出队列点3、容量固定4、有两个等待队列,分别用来在入队以及出队后分别进行唤醒5、因为是阻塞队列,当没有数据取的时候,线程会加入到一个等待数据的

2022-01-24 17:52:15 644

原创 ReentrantLock源码解析

ReentrantLock源码解析ReentrantLock是一个轻量级锁,主要采用同步队列,以及CAS去进行资源的争夺重要内部类Sync //重要,我们的ReentrantLock的加锁解锁基本靠这个 abstract static class Sync extends AbstractQueuedSynchronizer { //加锁方法,被abstract修饰,需要子类实现 abstract void lock(); //不公平的尝试获取锁,final修饰,代表不能被重写

2022-01-21 17:38:25 652

原创 AQS源码解析

AQS源码解析一、AQS是干什么的?AQS是一个同步抽象队列,简单来说就是一个队列,而且是FIFO的双向队列,也就是AbstractQueuedSynchronizer这个类队列的话肯定会有节点,它又是一个同步性质的队列,所以他的节点就是由我们想要获取锁这种资源的线程包装而来的我们的线程会然后尝试获取同步状态,没有获取成功的会被包装成Node节点,然后加入到我们的队列,并进入等待状态,直到被唤醒那么他们想获取到的资源是什么呢?在AQS中,有一个被volatile修饰的state变量,这个就是我们

2022-01-20 17:58:52 446

原创 集合中的快速失败和安全失败

集合中的快速失败和安全失败快速失败当使用迭代器遍历集合的时候,如果在这个遍历的过程中,进行了修改,就会直接抛出ConcurrentModificationExecption原理:在HashMap中,我们每次进行操作的时候,会维护一个modCount,当我们对HashMap进行了修改之类的操作,就会将这个值进行++,当我们迭代的时候,会判断这个值是否发生了改变,改变了就会抛出异常安全失败在JUC包下的这些容器都是安全失败,可以在多线程的情况下使用,并发修改对集合结构的修改会在一个复制的集合上

2022-01-17 18:08:47 394

原创 ThreadLocal源码深度解析

一、介绍ThreadLocal叫做线程本地变量,会给每个线程都分配一个属于自己的本地变量,用于线程变量隔离,保证线程安全每个线程内部都会有自己的一个ThreadLocalMap,然后key是ThreadLocal,Value是我们自己设定的值,注意Entry中Key是弱引用,弱引用是发现就回收,继承了WeakReference这个,但是V不是,所以这里可能会产生简图Thread.class /* ThreadLocal values pertaining to this thread. Thi

2022-01-17 17:45:47 372

原创 策略模式+工厂模式的组合使用

策略模式+工厂模式的组合使用**策略模式:**定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。个人感觉特别好用,当你在一段代码中,有很多的候选算法,你就可以用这个策略模式了,可以有效的取出if…else这样的条件分支**工厂模式:**定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行这个设计模式就很常见了,像我们的Spring中就用到了工厂模式这里就直接上代码了首先是枚举类 public enum IdGeneratorTypeEn

2021-12-22 14:21:54 1511

原创 并发容器——ConcurrentHashMap

并发容器——ConcurrentHashMap在以往的java.util下的容器,例如HashMap,它是一个线程不安全的容器,在1.7因为头插法导致了可能出现的死循环,因为没有进行线程安全的一些控制,所以会出现一些问题,但是有一个HashTable,这个类在HashMap的基础上,给每个方法都增加上了Synchronized关键字,但是每次操作都会进行加锁解锁,并且,锁的粒度很大,就会导致锁冲突,多个线程会共同抢夺锁,性能比较差,所以道格李大师就提出了新的并发容器,ConcurrentHashMap这

2021-12-19 19:26:45 691

原创 负载均衡——一致性Hash算法

负载均衡——一致性Hash算法讲一致性Hash之前要先将Hash,对于Hash来说,只需要O(1)的时间复杂度,然后就能计算出结果,像我们的HashMap中,在计算key的下标时,用到hash算法,不过那个是计算了hashcode后然后将hash值进行散列,其实也都差不多,对于同一个key,每次计算的结果都是一样的,这个就是一致性,但是对于一致性Hash,比Hash又多了些什么东西呢普通Hash:假设我们有3台服务器,我们可以像HashMap中添加元素那样,利用key的Hash来计算出下标,因为同一个k

2021-12-19 00:18:50 537

原创 集合(二) —— LinkedList

集合(二) —— LinkedListLinkedList是一个双向链表,结点类是Node优点:插入元素和删除元素比ArrayList在一般情况下要好缺点:遍历和随机访问要效率低,因为和ArrayList比较,没有数组的下标机制来进行访问,需要通过next指针遍历(PS:上面的效率是不排除意外情况,理论上一般情况下的结果,因为有看到部分测试结果比其他的要稍微差,但个人没有测试)(一)重要内部类Node:LinkedList是一个双向链表,所以肯定需要一个结构来作为存储指针以及元素。 priva

2021-12-17 17:56:35 513

原创 限流——令牌桶算法

限流——令牌桶算法令牌桶简单来说就是有一个桶,然后假设里面存放了1000个令牌,我们访问一个接口需要有一个令牌,然后令牌桶中就会减少1个令牌,所以最多只能有1000个请求拿到令牌,但是,我们一般不会只有1000个令牌,所以,我们还需要设置每隔一段时间就会自动生成令牌然后我们使用lua+redis来进行令牌桶限流代码的编写这里使用的是springboot,先上代码TokenBucket.class@Slf4jpublic class TokenBucket { //当前令牌桶的key

2021-12-17 16:45:22 1705

原创 集合篇(一)——ArrayList

集合篇(一)——ArrayListArrayList是一个在内存中连续分配的Object数组,优点:在遍历元素和随机访问元素的效率高,因为是数组,访问时只需要根据下标进行查找就行,缺点:在添加和删除元素时,就需要进行移动大量元素,在java中是利用Arrays.copyOf()方法以及System.arraycopy方法来进行移动,开销大下面是ArrayList的源码(一):重要属性 //修改次数 protected transient int modCount = 0; //链

2021-12-17 15:57:53 266

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除