- 博客(62)
- 收藏
- 关注
原创 Thread及其相关类
Thread中除了创建平台线程的内部构造器之外,还有一个创建虚拟线程的内部构造器,这个构造器不能通过new Thread调用,只能通过Thread.ofVirtual()或Thread.startVirtual()调用(这些内部构造器都是不public的)JavaThread和Thread是互相持有的,而Thread类中的eetop这个字段指向的就是JavaThread的地址,如果eetop的值为0的话,表示未关联JVM内部的线程对象。虚拟线程忽略线程优先级、守护状态等这些概念。分为守护线程和非守护线程;
2025-12-16 16:26:03
728
原创 java8新特性
(例如在一个类中创建一个线程,实际创建了一个runnable接口的匿名内部类,这个匿名内部类会持有这个外部类对象的引用,所以即使这个对象可以被回收,但是创建出来的线程仍然没有停止的话,这个对象会一直被持有强引用,无法被回收)的匿名内部类的地方来说实际是一个函数式接口的实例,但是我们只关注这个实例中对抽象方法重写的逻辑部分,所以对于new一个这个接口的实例这部分我们没有那么关注,更关注重写的这部分函数逻辑)主要区别是语义上的区别,抽象类解决的是是什么问题,接口解决的是能实现什么功能的问题。
2025-12-15 21:02:31
970
原创 nacos服务注册中心
其中RestTemplate方法实际是通过拦截器来拦截发送的http请求(这个拦截器与SpringMVC中的拦截器不同,SpringMVC中的拦截器是在处理http请求前后拦截的,RestTemplate的拦截器是在发起http请求前后拦截的):SpringCloud在启动的时候,会检测到带有@LoadBalanced的RestTemplate,并自动为其添加一个LoadBalancerInteceptor。Feign方法不是走拦截器的方式,而是通过代理的方式,拦截client的方法。
2025-12-14 14:22:52
222
原创 Spring事务
Spring支持的事务本质上是数据库支持的事务,所以前提也是数据库支持事务Spring,而是通过所以 Spring 的事务是的设计典范。Spring支持两种方式的事务管理:编程式事务管理(使用硬编码的方式)和声明式事务管理(使用注解@Transactional的方式)
2025-12-12 23:23:18
389
原创 为什么redis使用跳表mysql使用b+树:几种搜索的数据结构的对比
同时由于非叶子节点中只存放键,所以数据页中就可以放更多的键,从而只访问一个节点,就可以排除大量的键,树的高度也更低了,磁盘的访问次数也大大减小。磁盘场景下的搜索情况与内存有明显差异,因为内存读取不同节点都是在内存中,速度很快,但是如果在磁盘中的话,加载不同的节点就非常慢了,所以这种情况下就需要在一个数据页中存放尽量多的数据,从而避免多次加载数据页。avl树要求的是绝对的平衡,左右子树高度差不能超过1,但是这种要求有的时候对实际的搜索太严格了,而且实际应用中很少有只搜索的,大部分都是。
2025-12-11 21:21:28
738
原创 为什么java中不使用多叉树
二叉树和多叉树在查找时间复杂度来说都是O(logn),对于内存来说访问速度不是限制,但是内存资源是会稍微紧张一些的,多叉树的一个数据块中存放多个数据,一个数据块如果太大,容易存在内存碎片,所以内存中更适合单个数据作为一个节点。对于java中一些数据结构,它们与数据库的主要区别是数据量小,其次java的垃圾回收机制也更支持单数据节点的实现方式,且红黑树的性能和稳定性都很高了,没有必要再设计一种适合java的多叉树了。一个节点的左子树的所有节点的都小于这个节点,右子树的所有节点都大于这个节点。
2025-10-04 20:16:33
261
原创 操作系统进程与线程,java线程与操作系统线程
调用start方法之后,通过JVM的本地方法向OS申请并启动一个新线程,并把它与该 Thread 对象关联,从NEW状态转化成RUNNABLE状态。关于线程的六种状态是Java 层面对“某个 Thread 实例所代表的线程执行情况”的抽象视图,不能直接说是os中线程的状态。在new Thread()方法中实际对应的线程概念有两个,一个是在堆上创建的线程对象,一个是对应的操作系统线程。所以NEW状态对应的是new thread()后创建的一个线程对象。Java创建的线程实际上对应的是操作系统的原生线程。
2025-09-02 14:59:14
136
原创 java即时编译器
默认设置下,方法调用计数器统计的不是方法被调用的绝对次数,而是一个相对的执行频率,当超过一定的时间限度,如果方法的调用次数不足以进行编译的话,该方法的调用计数器就会被减少一半,这个过程称为调用计数器热度的衰减,这段时间就是半衰周期,一般是在垃圾回收的过程中顺便进行的。当解释器遇到一条回边指令时,会先查找将要执行的代码片段是否有已经编译好的版本,如果有的话,它将会优先执行已编译的代码,否则就把回边计数器的值加一,然后判断方法调用计数器与回边计数器值之和是否超过回边计数器的阈值。·基于计数器的热点探测。
2025-08-29 11:45:58
649
原创 jvm锁优化
补充:逃逸分析是比较复杂的,但是程序员为什么会在没有并发冲突的情况下去加锁呢,是因为有些程序员写的代码没有共享数据,但是不代表没有同步操作,例如String字符串的+法,是会转成StringBuffer的append,JDK5之后改成StringBuilder,StringBuffer的append是有锁的,但是实际上这部分代码是不存在数据竞争的情况的,所以进行锁消除。此时MW里的对象的哈希值就没了,存的是线程的id,那要是如果还需要用到哈希值的时候,他的偏向锁就会被撤销,升级为重量级锁。
2025-08-28 16:21:21
798
原创 负载均衡
(一致性hash,就是将所有节点计算出hash值标在0-2^32-1的环上,然后每次来请求之后也计算出hash,顺时针找距离哪个节点最近就转发到那个后端节点上,这样的话只有部分请求转发的节点会改变,剩下的都是不变的)哈希和一致性哈希的区别:主要区别是在节点数量发生变化的时候,普通hash的几乎所有key都要充型映射,就会导致大规模缓存失效、数据迁移;nginx是L7层负载均衡,工作在OSI模型的第7层(应用层),依赖完整的HTTP请求、响应来进行转发,可以实现内容路由(根据不同的url转发到不同集群)
2025-08-24 21:12:06
320
原创 线程安全与锁优化
也就是数据必须是共享的,但是当线程A获得这个数据之后,无论怎么处理都不会把这个数据放回去或者由其他线程处理。多个线程同时访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,就称这个对象是线程安全的。随着硬件指令集的发展,另一种并发策略——基于冲突检测的乐观并发策略,不管风险,先进行操作,如果没有其他线程共享数据,就操作成功,如果有冲突,再进行其他的补救措施,最常见的是不断重试。
2025-08-18 10:18:22
890
原创 Java线程
有了线程之后,可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址、文件IO),又可以独立调度是java里处理器资源调度的基本单位每个已经调用过start()方法且还为结束的java.lang.Thread类的实例就代表一个线程。
2025-08-14 16:39:39
686
原创 Java内存模型
虽然指令重排序会导致指令执行的顺序发生变化,但是不是任意指令的顺序都是乱序的,在有数据依赖关系的指令先后顺序是保证的,比如指令A给变量+10,指令B给变量*2,那这两条指令的执行顺序会影响变量最后的结果,这样的指令之间的顺序是不能改变的,但是如果指令C操作另外的变量,这个时候把指令C放到指令AB的任意地方都是可以的。use(使用):作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引 擎,每当虚拟机遇到一个需要使用变量的值的字节码指令时将会执行这个操作。
2025-08-04 14:38:34
634
原创 mysql索引下推和索引失效
使用非聚簇索引的时候,b+树的叶子结点是主键索引的值,例如一个联合索引(a,b,c),如果只匹配到a,那么即使where条件中有c的条件,也不会在这个时候进行过滤,只会根据a的索引得到所有主键id,然后返回给服务器,服务器再根据主键id去查询所有数据,返回到服务层再进行过滤,这个过程就是回表。如果是非聚簇索引的话,在联合索引(a,b,c)中虽然只匹配到a的索引,但是可以获得c字段的值,也可以通过where中c的值进行过滤,返回更少的主键id给服务器层去进行回表。只会匹配到索引a,索引b不会生效。
2025-07-30 19:19:43
740
原创 mysql
DB_TRX_ID: 事务id,记录最后一次插入或更新该行的事务id,每次对数据进行修改时,都生成一个新的版本,将这个字段更新为当前事务的id。是一个快照,记录了系统中所有活跃事务的id列表(已经启动但是尚未提交的事务),通过比较DB_ROW_ID和read view,可以决定这个版本的数据是否可见。写:innoDB在写数据的时候会对记录加锁,在获得行的写锁之后才能进行修改,事务提交或者回滚之后才能会把这个行的写锁释放,其他事务才能继续修改这个行。
2025-07-24 13:59:08
2007
原创 java垃圾收集器
region中还有一类特殊的humongous区域,专门用来存储大对象,G1认为只要大小超过一个region容量一半的对象即可判定为大对象,要是超过整个region容量的超级大对象,就会被存放在N个连续的humongous region中,G1大多数把这块区域作为老年代的一部分。G1开创的基于Region的堆内存布局,把连续的java堆划分为多个大小相等的独立区域(region),每个region都可以根据需要,扮演新生代的Eden,Survivor或者老年代。2.CMS无法处理浮动垃圾。
2025-07-21 15:39:28
695
原创 java垃圾回收(一)
对于内存区域,程序计数器、虚拟机栈、本地方法栈都是与线程相关的,每个栈帧占多少内存基本上是在编译期间就确定的,栈帧的建立和回收都与方法的调用和返回紧密联系,这部分不是垃圾回收重点关注的地方但是java堆和方法区具有很强的不确定性:一个接口的多个实现类需要不同的内存一个方法所执行不同的条件分支所需的内存也是不确定的只有在运行期间,才知道会创建哪些对象,创建多少对象所以垃圾回收主管关注这部分内存。
2025-07-11 14:44:59
841
原创 java agent技术(二)
premain的主要作用是注册一个或多个ClassFileTransformer,但是这些transformer不会立刻执行,而是在之后类被加载的时候才会触发。3.如果任何一个transformer返回了新的字节码数据,JVM就使用这个新的字节码去定义类(defineClass)premain发方法是在JVM启动的时候运行的,但是真正产生修改字节码的动作是在类被加载的时候发生的。是有效的,如果重新启动JVM的话,没有使用这个agent还是加载的原始的class文件。注册了这些transformer之后,
2025-06-13 14:40:18
364
原创 string和常量池
常量池的本质就是一个类似HashMap<String, WeakReference<String>>的结构(但是这个表是native实现的,不是java层面的HashMap)java中的字符串常量池是由JVM维护的一个特殊的数据结构,用于缓存字符串对象,以减少重复内存开销。所以就可以理解为什么字符串常量池是在堆中了,因为字符串常量池中存的都是string对象的引用。去常量池中查找是否有相同内容的字符串的时候,语义上使用的等价于equals方法。在JDK6以前,会复制字符串到常量池,返回常量池中的副本。
2025-06-10 20:08:55
262
原创 JVM内存区域
运行时常量池相对于class文件中的常量池还有一个重要特征是具备动态性,class文件中的常量池的内容是在编译期确定的,这个常量池加载到虚拟机中成为运行时常量池,但是运行时常量池的内容不仅仅只是编译期确定的,运行时也可以生成新的常量放入池中。,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小(这里说的“大小”是指变量槽的数量,一个变量槽多大由虚拟机自行实现)。如果执行的是java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;
2025-06-10 10:14:58
816
原创 java的迭代器
这是因为arraylist内部使用一个modCount的字段记录集合被修改的次数,迭代器内部也维护了一个对modCount的引用,每次next()或hasNext()都会检查当前这个modCount和迭代器创建时的expectedModeCount是否相等,不想等就抛出异常【所以抛出异常的时机是迭代器执行next()或hasNext()的时候,不是修改集合的时候】迭代器访问的是集合的一个副本或视图,因此对原始集合的任何修改都不会影响正在进行中的迭代过程。,底层实际上是获取iteraior进行遍历。
2025-06-04 11:21:03
410
原创 java的SPI机制
SPI(Service Provider Interface)是java提供的一种服务发现机制。允许你定义一个接口或抽象类,然后由第三方实现这个接口,并在运行时动态加载这些实现类是:面向接口编程,解耦接口与实现。
2025-06-03 14:44:41
309
原创 MongoDB及spring集成
MongoDB 是一个基于的开源 NoSQL 数据库系统用文档存数据,每个文档可以看作是一个键值对集合,类似于 JSON 对象MongoDB 支持索引以提高查询性能,并且可以在任何属性上创建索引。
2025-05-19 10:05:23
969
原创 linux学习
linux指的是基于linux内核构建的一系列完整的操作系统发行版linux内核只负责管理硬件资源,提供基本的操作系统服务以及为用户程序提供运行环境在linux系统中,一个核心概念就是“一切皆文件”,无论硬件设备、目录、普通文件还是网络连接等,通过统一的接口进行访问和管理,极大地简化了系统的设计,通过一套通用的文件操作命令来与各种资源交互普通文件:包括文本文件、二进制文件、脚本文件等目录:特殊的文件,包含了其他文件或子目录的引用设备文件:表示硬件设备,分为字符设备和块设备。
2025-05-15 17:24:33
559
原创 contains方法的实现对比
contains方法定义在Collection接口中,所有实现了该接口的集合类都支持contains方法在Java中,不同的数据结构实现contains方法的方式各异,这直接影响了它们的时间和空间效率。下面我们将详细探讨几种主要的数据结构(如ArrayListLinkedListHashSetTreeSet等)的底层原理及其在执行contains操作时的表现。List。
2025-05-14 15:30:59
388
原创 常见的几种网络攻击
具体来说就是用户点了恶意链接之后,会把正常的URL中的某个参数修改成一段js代码,这个请求发送给服务器之后,服务器可能会把这段js代码当作一个普通的参数返回给用户,等到用户收到服务器的返回并且解析响应的时候这段js代码可能就会执行,从而对用户的浏览器发起攻击。在早期的web安全模型中,浏览器的安全机制主要依赖同源策略,即一个页面的脚本只能读取或修改来自同一来源(相同协议、域名和端口)的资源,然而XSS攻击打破了这种隔离,是的恶意脚本可以在不同的站点上下文中执行,从而影响到其他站点的数据和行为。
2025-05-14 14:19:08
890
原创 RASP的运行时注入与更新
背景:java中类加载器并不提供卸载单个类的功能,但是一个类加载器不再被引用并且可以被垃圾回收时,它所加载的所有类也会被一同回收,所以如果想卸载某个类,可以通过丢弃整个类加载器实例,并确保没有对该类加载器或其加载的任何类的强引用,这样垃圾回收器就可以回收这个类加载器及其加载的所有类。更新插件到V1.1版本,首先确保没有对旧版本插件对象的引用,下一步销毁当前使用的自定义类加载器,接下来创建一个新的自定义类加载器实例,用这个新的类加载器实例来加载新版的插件,再执行必要的初始化逻辑,此时新的插件就开始生效了。
2025-05-13 16:05:46
490
原创 agentmain对业务的影响
前面一篇已经说了java agent技术主要有premain和agentmain两种形式,如果大部分业务已经在线上运行的话,不方便用premain的方式来实现,所以agentmain的方式是更加通用、灵活的由于RASP是与用户业务运行在同一个jvm中的 ,所以RASP会严重影响用户业务的执行情况,如果RASP崩溃的话那么业务程序也会收到严重毁灭性的影响。对业务上的影响主要包含cpu占用和耗时方面的影响。
2025-05-13 10:01:33
1908
4
原创 java agent技术
从JDK1.5之后引入了java angent技术Java Agent 是一种强大的技术,它允许开发者在或动态地修改类的字节码,从而实现诸如性能监控、日志记录、AOP(面向切面编程)等功能java agent依赖于,是 Java 提供的一个用于操作已加载类的字节码的标准API。通过这个API,你可以修改类的字节码,甚至可以在不重启应用的情况下重新定义已经加载的类具体的实现过程是通过一个agent来对字节码进行修改,agent实际上是一个特殊的jar包,包含了一个或多个特定的方法(premain或。
2025-05-12 14:50:03
533
原创 class文件(二)
java中的重载除了要与原方法具有相同的简单名称之外,还要求必须拥有一个与原方法不同的特征签名,特征签名是指一个方法中各个参数在常量池中的字段符号引用的集合,因为返回值不包含在特征签名中,所以java不能仅靠返回值来进行方法重载。去常量池中检索可以得到这个方法名是<init>,描述符为()v,表示没有参数没有返回值,属性名对应常量为"Code",说明这个属性是方法代码的字节码描述。这个方法有一个u2类型的参数说明调用哪个方法,指向常量池中的一个Methodref_info(此方法的符号引用)
2025-04-23 20:55:37
927
原创 class文件(一)
class文件是一组以的二进制流,没有任何分隔符,如果遇到需要占用8个字节以上空间的数据项时,会按照高位在前的方式分割成若干个8个字节进行存储class文件格式采用一种类似于C语言结构体的伪结构来存储数据,只有两种数据类型:“无符号数”和“表”无符号数:基本的数据类型,以u1,u2,u4,u8分别代表1、2、3、8个字节的无符号数表:由多个无符号数或者其他表作为数据项构成的复合数据类型。
2025-04-21 15:45:08
985
原创 函数式编程——lambda表达式
同门在面试腾讯的时候被问到jdk8最大的新特性是什么,应该就是lambda表达式了吧lambda表达式是一种代表函数的接口,可以代替某些匿名内部类对象(被重写方法的形参列表)->{被重写方法的方法体代码}lambda表达式只能替代的匿名内部类函数式接口:有且仅有一个抽象方法的接口@FunctionalInterface注解可以声明这个接口是一个函数式接口。
2025-04-14 16:20:05
392
原创 继承(this和super)
(这里注意,只有在父类的成员变量子类也拥有的时候,会把父类的隐藏掉,通过super来实现显式的调用,但是如果父类的成员变量子类没有的时候,就不会隐藏了,直接显式显示,这也就是为什么前面例子中fatherName前面没有Father.但是name前面有Father.,因为子类也有name,但是子类没有fatherName,如果给子类也加上fatherName这个属性的话,就是下面这样)发现会会报错,提示缺少‘.’,可以看出super并不是一个实例的引用,只是一个特殊的指示符,用于在子类中访问父类的成员。
2025-04-14 13:28:54
374
原创 java内部类
就是一个成员变量,不过这个成员变量是一个类内部类可以访问外部类的所有成员,包括私有成员编译之后可以看到产生了两个class文件(所以内部类实际上是可以和外部类同名的,因为编译之后内部类前面还会加上外部类的名字,所以可以做到区分):对内部类的class文件进行反编译这里要区别一下和的区别,子类只能访问父类的public和protect修饰的,但是内部类还可以访问私有的<关于继承和隐藏我后面再研究一下应该还会出一个帖子>
2025-04-14 11:07:06
362
原创 阅读redis源码——String
redis中最常用的五种数据类型:String、List、Hash、Set、Sorted Set这是一个通用函数,用于实现SETSETEXPSETEXSETNX和GETSET等命令。'flags':区分不同的行为(如NXXXGET等)。'expire':表示以用户传递的 Redis 对象形式设置的过期时间,'unit' 进为时间单位如果设置了GET选项,它会先获取键的当前值,然后再设置新值。大概的流程图是这样的调整参数列表:为了确保命令再持久化或复制到从服务器能够正确执行。
2025-04-13 17:06:56
872
原创 JVM指针压缩
首先先理解一下操作系统是怎么寻址的,以32位的操作系统为例,32位(4个字节)可以表示出2^32个不同的地址,内存的基本计量单位是字节,也就是每个内存地址对应的是 8 位的存储空间,所以2^32个地址可以表示2^32字节的内存空间,也就是4GB的内存空间,所以【结论:4个字节可以表示4GB的内存空间】JVM指针压缩说的是对象头中的【klass word】部分的指针压缩,在jvm内存小于32G的时候默认会开启指针压缩,将【klass word】8字节的指针压缩为4字节的指针。(32G内存的条件下)
2025-04-12 22:29:03
368
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅