- 博客(143)
- 收藏
- 关注
原创 4.7 从三大日志开始考察
当我们要查询一个数据的时候,我们会返回当前数据行的readView,会与最小的活跃事务id进行比较,如果当前事务id小于这个最小活跃事务,我们需要通过roll_pointer沿着undolog找到合适的事务id。再深入一点,在一个事务A执行的过程,一个数据很可能被修改了很多次,我们需要怎么去比较一个数据可不可读,这个时候就要用到readView,readView里面有所有事务id和活跃事务id。事务T1读取A,事务T2修改了A的数据,但是没有提交,但是事务T1一直读到都是没被T2修改的数据。
2025-04-08 09:05:19
160
原创 Redis单线程为什么能这么快
3.Redis采用了多路复用机制,一个线程监听多个通道,能并发处理大量的客户端请求。然后我们通过一个循环来不断轮询(不断检查各个IP通道的状态,决定操作是否需要执行)2.选择了很多高效的数据结构,一种对象底层有几种实现以应对不同场景。主要是第三点,单线程我们会在哪里阻塞,多路复用又帮了我们什么?一般来说,客户端发送数据,我们需要三个过程来进行读取,分别是。每次IO操作触发,产生通知,通知就会触发另外一些操作。我们使用非阻塞模式,如果没数据,就不会阻塞在那里。Redis在内存中处理数据,I/O是瓶颈之一。
2025-01-21 13:09:17
317
原创 Redis内存面试与分析
分析:首先,redisDb代表的是Redis的数据结构,我们主要关注dict这个数据结构还有一个expires存储的是我们的过期值,这个也要记住在 Redis 中有hash和set类型的字典,每种类型的字典操作(如计算哈希值)可能不同。
2025-01-21 12:51:59
1045
原创 1.18 从零钱兑换开始
j++){ //装满一个背包是小于这个背包容量的背包凑上来的 //dp[i] + dp[i-nums[j]] <Integer.MAX。*/ class Solution { //dp[0] == 1表示如果dp[j-coints[i]] = dp[0] 表示背包容量为j,刚好有一种方法可以填充 public int change(int amount,int[] coins) { int max = Integer.MAX_VALUE;
2025-01-18 13:43:38
447
原创 1.13 从监控二叉树开始
2.左右节点有一个是摄像,另一个是摄像或者覆盖,return 2。左右孩子有一个没有覆盖-》父节点放摄像相机。3.左右节点有一个为空,return 1。尽量让叶子节点的父节点变成摄像头。左右节点有覆盖,父节点就应该是2。1.如果是叶子节点,直接返回2。叶子节点固定为有覆盖的值2。数字从倒数第二位遍历。
2025-01-14 10:44:37
205
原创 1.13 从MySQL事务隔离级别开始
select查询是通过**MVCC(多重)**实现的,在MVCC实现中,每条记录都会有一个版本号,启动时读取了哪个版本号,过程中会一直看开始时候的版本号,从而保证了事务的隔离级别。可重复读隔离级别是在开启事务之后,执行一条select语句之后,生成一个Read View,后续事务查询数据都复用这个Read View,所以保证了事务期间多次读到的数据是一致的。脏读是一个事务读到了另一个未提交事务修改过的数据,如果另外一个事务回滚了,刚才读到的数据就和数据库里面的数据不一样了。可重复读避免了脏读和不可重复读。
2025-01-14 10:43:16
279
原创 @Bean注解的是构造器方法?
Bean注解的方法是一个普通方法,只不过这个方法返回了一个对象,我们将这个对象交给spring容器进行管理。Spring容器会调用这个方法来创建Bean。
2024-12-09 11:32:00
77
原创 Spring事务实现原理
因为方法调用的嵌套场景中可能涉及很多个业务方法,所以Spring需要通过传播行为来明确这些事务之间的关系。|每次调用都创建一个新事务,外部事务被挂起。,外部方法有事务时加入其事务,否则创建一个新事务。|在外部事务中嵌套事务,内部事务可以独立回滚但不会影响外部事务。|如果外部方法有事务,就加入;如果抛出业务,根据事务配置调用rollback()回滚事务。|暂停当前事务,以非事务方式运行内部方法。|必须在已有事务中运行,否则抛异常。|必须在非事务环境中运行,否则抛异常。负责事务的开启,提交和回滚。
2024-12-07 23:39:18
196
原创 Spring设计模式
prototype是spring的作用域,每次调用都是一个新的实例,同时,Spring只负责创建,调用者负责销毁。AOP(面向切面编程)能够与业务无关,需要将业务逻辑共同调用的逻辑或责任封装起来,目的是为了降低模块间的耦合度。表示一种对象与对象之间具有依赖关系,当一个对象发生改变的时候,依赖这个对象的所有对象也会作出反应。在我们的系统中,有一些对象我们只需要一个,比如线程池,缓存,对话框。适配器就是一个中间层,用来驱动,将老驱动适配为新系统支持的接口。对于频繁使用的对象,可以省略创建对象所花费的时间。
2024-12-07 23:18:49
304
原创 9.21 Day01
单调栈:通常是一维数组,当前遍历的元素,其左边或者右边需要找到一个比自己大或者比自己小的元素的位置,此时我们看可以用单调栈。每次判断栈顶的元素,如果当前元素(会将下标弄到数组中)大于遍历的元素,则将遍历的元素下标加入到栈中。如果大于栈中的当前元素,栈中的下标会弹出并直接记录到res[stack.pop()] = i;鄙人认为这道题不需要解释的很费劲,代码随想录看完以后(感觉解释的不好,可能也不好解释)然后for循环从第2个元素开始,遍历到最后面。然后将当前元素下标加入到栈中。肯定是递增的,从栈头到栈底。
2024-09-21 21:50:26
424
原创 内存区域-面试与分析
如果常量池中有等于此String对象的字符串,返回池中这个字符串的String对象的引用,否则将此String对象包含的字符串添加到常量池并返回此String对象的引用。,Java里几乎所有对象实例都在堆分配内存。堆可以处于 物理上不连续的内存空间,逻辑上应该连续,但对于数组这样的大对象,多数虚拟机实现处于简单,存储高效的考虑会要求连续的内存空间。堆是虚拟机所管理的内存中最大的一块,被所有线程共享的,在虚拟机启动时创建。方法区主要存放类型信息,如类名,访问修饰符,常量池,字段描述,方法描述等。
2024-09-13 18:36:21
852
原创 JVM-内存区域
方法区的大小和堆空间一样,可以选择固定大小可选择扩展,方法区的大小和对空间一样,可以选择固定大小也可以选择可扩展,方法区的大小决定了系统可以放多少个类,如果系统类太多,导致方法区溢出,虚拟机同样会抛出 内存溢出OutOfMemoryError错误。本地方法栈与虚拟机栈所发挥的作用是非常相似的,区别只是虚拟机栈为虚拟机执行Java方法,本地方法栈则是为虚拟机使用到的本地方法(Native)方法服务。当调用一个新的方法时,就构建一个栈帧压入到栈中,而一个方法执行结束,就会有一个栈帧出栈,整个遵循FIFO原则。
2024-09-13 16:47:06
1240
原创 Java并发复习
这里有两个并发,一个是进程的并发,一个是线程 的并发进程:对运行时的程序进行封装,是系统进行资源分配的基本单位,实现了操作系统的并发;线程:进程的子任务,是CPU调度的基本单位,用于保证程序的实时性,实现进程内部的并发;在多线程编程中,一般线程的个数大于CPU核心的个数,而一个CPU核心在任意时刻只能被一个线程使用,为了能让这些线程都有效的执行,CPU采用的策略是为每个线程分配时间片并轮转的形式。当一个线程 的时间片用完的时候就会重新处于就绪状态让其他线程使用,这个过程就属于一次上下文切换。
2024-09-10 17:16:42
1051
原创 Java线程池和Executor框架-面试与分析
在Java并发框架中,线程池时使用最多的东西,几乎所有需要异步并发执行任务的程序都可以使用线程池。
2024-09-07 21:49:10
1045
原创 ScheduledThreadPoolEcecutor具体实现
嗯哼~开讲ScheduledThreadPoolExecutor会把调度的任务放到一个DelayQueue(core)中。我们对这四个步骤进行文字说明:源码:take()执行示意图:获取任务只要分成3步:1.获取Lock2.循环中获取周期任务add()示意图:添加任务分为3大步骤:FutureTask为Future提供了基础实现,如获取任务执行结果和取消任务等。如果任务尚未完成,获取任务执行结果时将会阻塞,一旦执行结束,任务就不能被重启或取消。FutureTask常用来封装Call
2024-09-07 18:58:16
844
原创 阻塞队列的实现原理
*使用通知模式实现。**所谓通知模式,当消费者从空的队列获取元素时会阻塞住消费者,此时如果生产者放了一个元素进入队列,则需要通知被阻塞的消费者当前有元素可取。同理,当生产者往满的队列里添加元素时会阻塞住生产者,当消费者消费一个队列中的元素后,会通知生产者当前队列可用。如果队列是空的,消费者会一直等待,当生产者添加元素时,消费者是如何知道当前队列有元素?
2024-09-01 23:09:55
154
原创 Java中的阻塞队列BlockingQueue
阻塞队列是一个支持两个附加操作的队列->支持阻塞的插入方法:当队列满时,队列会阻塞插入元素的线程,直到队列不满支持阻塞的移除方法:意思是在队列为空时,获取元素的线程会等待队列为非空->这两个附加操作提供了4种处理方式:**抛出异常:**当队列满时,如果再往队列里插入元素,会抛出IllegalStateException异常。当队列空时,从队列里获取元素会跑出NoSuchElementException异常。
2024-09-01 23:00:07
377
原创 ConcurrentHashmap面试【高频】
红黑树所占的空间虽然是链表中Node所占空间的两倍,虽然红黑树的**查找效率为o(logN),要优化链表的o(N),**但是当链表的长度比较小的时候,即使全部遍历,时间复杂度也不会太高。->所以需要寻找一个时间和空间的平衡,即在链表长度达到一个阈值之后再转换为红黑树。**之所以是8,**这个是研究者研究哈希碰撞的泊松分布,发现逐渐降低了->基本上不可能碰撞,如果发生了8次,这个时候说明由于元素本身和hash函数的原因链表的阈值是6。
2024-09-01 22:08:44
466
原创 ConcurrentHashMap解析
这个上面的就是源代码进行再散列,目的是减少散列冲突,使元素能够减少散列冲突,使元素均匀地分布在不同的Segment上,从而提高容器的存取效率。先进行一次再散列,然后使用这个散列通过散列运算定位到Segment,再通过散列算法定位到元素。使用modCount这个中间变量,对于添加,删除,修改这些操作都对modCount进行加1.默认16,决定了segment的数量,最多支持16个线程并发写,一旦初始化,就不能再扩容。Segment中的哈希表使用的,refresh——>对哈希表(底层是数组)扩容。
2024-09-01 17:34:58
750
原创 并发容器简介
由于同步器的串行化严重降低了并发性,Java之后推出了多种并发容器,使用并发容器来替代同步容器,可以提高绳索性并降低风险J.U.C包中提供了几个非常有用的并发容器作为线程安全的容器:J.U.C包中提供的并发容器命名一般分为三类:如果对数据有一定的要求,则需使用Hashtable;在大部分场景通常都是弱一致性,使用ConcurrentHashMap即可;如果数据量在千万级别,且存在大量增删改操作,则可以考虑使用ConcurrentSkipListMap读多写少用CopyOnWriteArrayList
2024-08-30 19:25:01
283
原创 Lock接口和synchronized同步 对比它有什么优势?
Lock接口比提供了。他们允许。可以具有完全不同的性质,并且 可以支持多个相关类的条件对象它的优势有:1.可以使锁更公平2. 可以使线程在等待所的时候3.可以让线程尝试获取锁,并在无法获取锁的时候立即返回或者等待一段时间4.可以在不同的范围,一不同的顺序获取和释放锁(lock)
2024-08-30 17:05:11
454
原创 第三章 乱码的前世今生-字符集和比较规则
需要解决两个问题:界定清楚字符范围,需要哪些字符将一个字符映射成一个二进制数据的过程也叫做编码,将一个二进制数据映射到一个字符的过程叫做解码同一个字符集可以有多种比较规则比如说二进制规则就是两个字符对应的二进制编码进行比较一些重要的字符集ASCII字符集:收录128个字符,包括空格,标点字符,数字,大小写字母和一些不可见字符GB2312字符集:兼容ASCII字符集,以及收录了汉字以及拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母。如果字符在ASCII字符集中,采用1字节编码。
2024-04-30 14:19:40
797
原创 第2章 MySQL的调控按钮-启动选项和系统变量
因为多个客户端可以同时连接到一个服务器程序,所以对于同一个系统变量,不同的客户端需要具有不同的值,这是很正常的事情。客户端设置了global的系统变量,并不会对已经连接上的客户端的系统变量产生影响,只会对后面连接的客户端产生影响。如果你和我一样启动不了,去计算机管理,点击服务,找到mysql80,右击启动就行,然后会发现,修改成功了。是用来显示服务器程序的运行状况的,所以他们的值只能由服务器程序自己来设置,程序员是不能设置的。如果我们在多个配置文件中设置了相同的启动选项,就医最后一个配置文件中的为准。
2024-04-30 14:16:39
953
1
原创 第一章——小白入门
但是当客户端断开连接,服务器并不会丢弃这个线程,而是将这个线程 缓存起来,当下一个客户端连接的时候,使用这个缓存的线程。语法解析之后,面对我们写的mysql语句执行效率不会太高的问题,mysql的优化程序会对我们的语句进行一些优化,优化 的结果就是生成一个执行计划。维护缓存需要造成开销,比如每次都要去查询缓存中的检索,然后又要更新这个缓存,维护该缓存对应的缓存区域。Mysql提供了各式各样的存储引擎,不同的存储引擎管理的存储结构可能不同,采用的存取算法也可能不同。客户端需要提供主机信息 ,用户名,密码。
2024-04-30 14:15:34
819
原创 slice
因为slice值包含指向第一个sllice元素的指针,传入的slice允许在函数内部修改底层数组的元素。slice不能比较,数组可以比较:数组的类型和数值都相同的时候才可以相等。一个零值的slice等于nil,一个nil值的slice并没有底层数组。一个nil值的slice的行为和其他任意0长度的slice是一样的。为什么向函数传递slice允许在函数内部修改底层数组的元素?复制的slice只是对底层的数组创建了一个新的slice别名。slice顶部位置对应slice的最后一个位置。
2024-04-28 09:44:13
206
原创 Map....
这是因为map可能随着元素数量增长而重新分配更大的内存空间,从而导致之前的地址无效。和slice一样,map之间不能进行相等比较,唯一的例外是和nil进行比较。map的迭代顺序是不确定的,并且不同的哈希函数实现可能导致不同的遍历顺序。map中的元素并不是一个变量,所以我们不能对map中的元素进行取址操作。map中的元素不是一个变量,我们不要能对它进行取址操作。如果key不存在,得到value对应类型的零值。如果key存在,得到key对应的value。使用内置的delete函数可以删除元素。
2024-04-28 09:41:24
171
原创 结构体..
set不包含键值对,而且每个值在set中都是唯一的,set的主要目的是知道这个元素是不是这个集合的一部分。一个命名为s的结构体不能包含s类型的成员,但能包含*s指针类型的成员,这可以让我们创建递归的数据类型。有些时候我们会嵌入匿名结构体的原因是此结构体中的方法我们可以使用。如果考虑效率的话,较大的结构体通常会用指针的方式传入和返回。如果结构体的成员是可以比较的,那么结构体也是可以直接比较的。如果要在函数内部修改结构体成员,用指针传入是必须的。
2024-04-28 09:40:43
149
原创 Json(标题)
将结构体转变为Json的过程叫编组,编组是通过json.Marshal函数完成的。json的对象类型可以用于编码Go语言中的map类型和结构体。Go语言对这些标准格式和编码都有良好的支持。json可以表示字符串,数字,布尔值和对象。类似的还有XML,ASN.1。是和在编译阶段关联到该成员的。
2024-04-28 09:39:35
374
原创 文本和HTML模板
这里是将Title作为prinf的参数,基于fmt.Sprintf实现的内置函数。可以简化这个err的处理,使用这个函数可以不需要管返回的err。模板语言里包含通过选择的结构体的成员,调用函数或方法。操作符表示将前一个表达式的结果作为后一个函数的输入。一个模板可能是一个文件或者是一个字符串。对于action部分将触发其他的行为。前面是输入的参数,后面是输出。是一个或多个由双括号组成的。我们呢来通过这个模板来分析。它接受一个模板和一个err。第一行是打印匹配到的总数。对应一个循环action。
2024-04-28 09:36:45
211
原创 函数(仅仅是将自己不会的写上去)
对squares的一次调用会生成一个局部变量x并返回一个匿名函数,中间的过程我们对外部的x进行了访问。函数值不仅仅是一串代码,还记录了状态。所以说函数值属于引用类型。函数值也就不可以比较了。我们将函数值成为闭包。
2024-04-28 09:36:04
107
原创 第二章 程序结构
抛开技术问题不说,基本的实现思路是,从每个包级的变量和每个当前运行函数的每一个局部变量开始,通过指针的访问路径遍历,是否能找到该变量。如果不存在这样的访问路径,说明该变量不可达,这样的变量也就没有存在的意义。指针是实现flag包的关键技术,它使用命令行参数来设置对应变量 的值,而这些命令行的标志参数可能会零散分布在整个程序中。新命名类型提供了一个方法,用来分割不同概念的类型,即使他们呢底层类型相同也是不兼容的。如果将指针作为参数调用函数,可以在函数中通过该指针来更新变量的值。通过指针来更新变量的值。
2024-04-28 09:34:22
246
原创 panic
panic异常发生的时候,程序会中断运行,并立即执行该goroutine中的defer函数。对于大部分漏洞,应尽量避免程序的崩溃,直接使用err(go提供的错误机制)panic函数接受任何值作为参数。
2024-04-28 09:32:05
125
原创 Recover捕获异常
我们很难完全遵守规范,在net/http包中提供的web服务器,我们不应该因为一个handler函数的问题而终止整个gorouitne,这里我们需要使用recover。下面这个函数中,如果某个异常出现,我们不会选择让解析器崩溃,而是将panic异常当作普通的解析错误,并附加额外消息提醒用户报告此错误。我们观察上面的defer函数,p是recover的错误信息,我们将panic value添加到了err中。在panic后面,我们无法保证包级变量的状态仍然和我们预期一致。我们需要有选择性的recover。
2024-04-28 09:31:05
205
原创 go圣经 ——方法
在第二组代码中我们将这两个变量联合起来变成了一个有mutex方法的 结构体变量,这是一个匿名的struct,同时我们又能使用mapping这个变量,使得结构更加统一。方法是与结构体相关联的函数,它允许我们从Rect类型的实例中选择并计算其面积。这里只是记录了自己学过一遍但是在圣经(狼吞虎咽)中又看到的新鲜玩意。比如都有max方法在Point和RGBA中,就会报错。我们的选择器可以不需要接收器就可以被调用。选择器中有多个同名的方法会报错。省略了上面的匿名函数。
2024-04-28 09:29:53
432
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人