Java反射 与 Lambda 函数映射

一、用「 Lambda 生成函数映射」代替「高频的反射操作」 我们来看一段最简单的反射执行代码: 上面的反射执行代码可以被改写成这样: fastjson2 中的具体实现的要复杂一点,但本质上跟上面一样,其本质也是生成了一个 function。 我们使用反射获取到的 Method 和 Lambda 函数分别执行 10000 次来看下处理速度差异: 处理速度相差居然达到 25 倍,使用 Java8 Lambda 为什么能提升这多呢? 答案就是:Lambda 利用 LambdaMetafactory 生成了函数映射代替反射。 下面我们详细分析下 Java反射 与 Lambda 函数映射 的底层区别。 1、反射执行的底层原理 注:以下只是想表达出反射调用本身的繁杂性,大可不必深究这些代码细节 如果要一句话解释的话,那就是通过元数据找到对应的方法,检查系统状态和反射参数没问题后就执行那个方法。 也就是说,正常执行一个方法的路径: java代码 => class字节码 => JVM解析字节码执行类加载过程 => 类加载获得元数据,JVM执行到对应的方法时根据元数据找到对应的方法开始执行 而反射执行的路径: java代码 => class字节码 => JVM解析字节码执行类加载过程 => JVM执行到反射部分的代码 => 通过反射系统拿到对应方法的元数据 => 检查系统状态和参数可以执行这个方法 => […]

MySQL InnoDB数据存储

这篇文章,理论上不是很难,MySQL是一个大块,这种零散的认识方式,终究需要一个系统的学习串起来。 转自 前言 大家都知道 MySQL 的数据都是保存在磁盘的,那具体是保存在哪个文件呢?MySQL 存储的行为是由存储引擎实现的,MySQL 支持多种存储引擎,不同的存储引擎保存的文件自然也不同。InnoDB 是我们常用的存储引擎,也是 MySQL 默认的存储引擎。本文主要以 InnoDB 存储引擎展开讨论。 InnoDB简介 InnoDB是一个将表中的数据存储到磁盘上的存储引擎。而真正处理数据的过程是发生在内存中的,所以需要把磁盘中的数据加载到内存中,如果是处理写入或修改请求的话,还需要把内存中的内容刷新到磁盘上。而我们知道读写磁盘的速度非常慢,和内存读写差了几个数量级。所以当我们想从表中获取某些记录时,InnoDB存储引擎需要一条一条的把记录从磁盘上读出来么?想要了解这个问题,我们首先需要了解InnoDB的存储结构是怎样的。 InnoDB采取的方式是:将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位innodb_page_size选项指定了MySQL实例的所有InnoDB表空间的页面大小。这个值是在创建实例时设置的,之后保持不变。有效值为64KB,32KB,16KB(默认值 ),8kB和4kB。也就是在一般情况下,一次最少从磁盘中读取16KB的内容到内存中,一次最少把内存中的16KB内容刷新到磁盘中。 InnoDB行格式 我们平时是以记录为单位来向表中插入数据的,这些记录在磁盘上的存放方式也被称为行格式或者记录格式。一行记录可以以不同的格式存在InnoDB中,行格式分别是compact、redundant、dynamic和compressed行格式。可以在创建或修改的语句中指定行格式: mysql5.0之前默认的行格式是redundant,mysql5.0之后的默认行格式为compact , 5.7之后的默认行格式为dynamic compact格式 记录的额外信息 记录的额外信息:分别是变长字段长度列表、NULL值列表和记录头信息 1:变长字段长度列表 mysql中支持一些变长数据类型(比如VARCHAR(M)、TEXT等),它们存储数据占用的存储空间不是固定的,而是会随着存储内容的变化而变化。在Compact行格式中,把所有变长字段的真实数据占用的字节长度都存放在记录的开头部位,从而形成一个变长字段长度列表,各变长字段数据占用的字节数按照列的顺序逆序存放 2:NULL值列表 NULL值列表:Compact格式会把所有可以为NULL的列统一管理起来,存在一个NULL值列表,如果表中没有允许为NULL的列,则NULL值列表也不复存在了。 为什么要有NULL值列表? 表中的某些列可能存储NULL值,如果把这些NULL值都放到记录的真实数据中存储会很浪费空间,所以Compact行格式把这些值为NULL的列统一管理起来,存储到NULL值列表中,它的处理过程是这样的: 3:记录头信息 名称 大小(单位:bit) 描述 预留位1 1 未使用 预留位2 1 未使用 delete_mask 1 标记改记录是否被删除 min_rec_mask 1 B+树非叶子节点中最小记录都会添加该标记 n_owned 4 当前记录拥有的记录数 heap_no 13 当前记录在记录堆的位置信息 record_type 3 […]

多核架构下的内存模型

参考 参考 一 走进多核编程 CPU 发展早期阶段,性能的提升主要来自于主频的提升和架构的优化,当这条优化途径出现瓶颈后,多核 CPU 开始流行起来。多核心同时执行任务极大地提高了系统整体性能,但也对硬件架构和软件编写提出了更大的挑战。各个核心都有自己的 Cache,以及不同层级的 Cache,彼此共享内存。一个典型的多核 CUP 架构如下图所示: 利用多核心的优势在各个核之间互相配合完成任务,如何进行各个核心间的数据同步(各个核心所属 L1 Cache/L2 Cache 数据的同步)是问题的关键所在。虽然发展出多种数据同步方式,以及流水线乱序执行的模式,但数据在各个核之间的一致性和可见性并不是那么理想;再加上编译器也会做优化,最终导致各个核的指令执行顺序和各个变量值的可见性变得不确定。 这种现象可以通称为重排,即原本应该有全序的内存读写操作被打乱。不过无论产生什么样的重排,都会保证对于单线程内部的执行结果不会有任何区别。下面是一个简单例子: 对于 Thread 1 内部,p 和 ready 没有关联,完全可以被重排而不影响正确性,而 Thread 2 依赖 ready 做标识位,一旦重排,Thread 2 在看到 ready 为 true 的时候 p 都可能没有 init,显然这是有问题的。 二 多核编程中临界区保护 利用多线程做并发的任务中通常都会有公共的临界区,比如最常用的一种数据结构:并发队列,生产者和消费者需要访问队列的公共内存进行写入和读取。目前对于临界区的保护方式通常可以分为三个级别:互斥、Lock-free 和 Wait-free。 1、 互 斥 互斥,顾名思义每个线程访问临界区之前都需要获得互斥锁,如果被别的线程占用了就阻塞等待。当进入临界区的线程发生阻塞,或被操作系统换出时,会出现全局阻塞,因为获得锁的线程被换出无法执行操作,而未获得锁的线程也只能一同等待,出现了阻塞传播。如果另一个线程先进入临界区,有可能反而可以更快的顺利完成。因为存在全局阻塞的可能性,采用互斥技术进行临界区保护的算法有着最低的阻塞容忍能力。 2、 Lock-free Lock-free 允许单个线程阻塞,但是会保证系统整体层面上的吞吐。如果当程序线程运行足够长时间的情况下,至少有一个线程取得了进展,那么就可以说这个算法是 Lock-free 的。如果一个线程被挂起,那么 Lock-free […]

MySQL的各种锁

转自 关于MySQL中的行锁、间隙锁这些之前一直不清楚,这篇文章讲的还是比较清晰的 这篇文章就来详细总结下 InnoDB 存储引擎中的行锁的加锁规则,并辅以实例解释。 首先众所周知,InnoDB 三种行锁: 哪些语句上面会加行锁? 1)对于常见的 DML 语句(如 UPDATE、DELETE 和 INSERT ),InnoDB 会自动给相应的记录行加写锁 2)默认情况下对于普通 SELECT 语句,InnoDB 不会加任何锁,但是在 Serializable 隔离级别下会加行级读锁 上面两种是隐式锁定,InnoDB 也支持通过特定的语句进行显式锁定: 3)SELECT * FROM table_name WHERE … FOR UPDATE,加行级写锁 4)SELECT * FROM table_name WHERE … LOCK IN SHARE MODE,加行级读锁 前置知识就不过多介绍了,在学习具体行锁加锁规则之前,小伙伴们需要记住加锁规则的两条核心: 1)查找过程中访问到的对象才会加锁 这句话该怎么理解?比如有主键 id 为 1 2 3 4 5 … 10 的 […]

lWoHvYe 无悔,专一