类的初始化以及静态变量优化
前言
JVM 规范中写道:在加载类的时候,分为如下几个大类:
- Creation and Loading
- Linking
- Initialization
每一步在 JVM 中都规定了具体的几个小节,但是今天本文的重点在于链接阶段,JVM 对一些静态变量做的一些优化,因此对于这里面的每一步具体是做什么的不展开讨论了。
JVM 规范中写道:在加载类的时候,分为如下几个大类:
每一步在 JVM 中都规定了具体的几个小节,但是今天本文的重点在于链接阶段,JVM 对一些静态变量做的一些优化,因此对于这里面的每一步具体是做什么的不展开讨论了。
在 Java 中,多线程的核心实现类是 ThreadPoolExecutor,该类提供了多线程的几个参数,用于开发人员自定义自己的线程池。
1 | public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime, |
线程池一共有 7 个参数,其中跟本次相关的有三个,分别是 corePoolSize、maximumPoolSize、keepAliveTime,这三个参数代表的意思如下:
ziplist 的添加过程大致如下:
如果是一个新建的 ziplist,其中新增元素的时候,直接将 prevlen 设置为 0 即可
如果是在中间位置新增,那么首先需要获取前一个 entry 的长度,因为后面的元素已经计算过了,因此直接拿来用即可
如果是在尾部进行新增元素,那么需要计算其前一个元素的长度,因为 zlend 不会保存前一个最后一个尾节点的长度,因此需要在新增的时候计算
由于 ziplist 的设计,当前一个元素长度小于 254 的时候, prevlen 会以一个字节进行存储,但是当前一个元素大于 254 的时候,那么 prevlen 就会变成 5 个字节
ziplist 是一个双向链表,但是不同于熟知的利用头指针和尾指针所形成的双向链表,ziplist 而是采用了一个特殊的实现
普通的双向链表因为在每一个节点上都含有一个头节点和尾节点,所以在遍历的时候可以依次沿着每一个节点进行递归,而且在新增或者删除的时候,直接移动指针即可,并且每一个节点在内存中并不要求是连续的,只需要指针指向对应节点的内存地址即可。
但是 redis 使用的是内存,在内存满了的情况下就会造成 redis 的不可用,需要依据淘汰策略清理内存。
试想下如果 ziplist 像普通的双向链表一样,每一次新增一个 entry 都去申请一块新的内存,实现起来确实比较简单。
String 是 Redis 中的基本数据结构之一,也是日常开发中使用最多的场景,例如秒杀扣库存,token缓存,详情缓存等,使用的频率还是比较高的,但是 Redis 中的 String 实现还是比较复杂的。
String 最底层的数据结构还是 char[],但是 Redis 在对数组进行封装的时候,做了一些细节上的优化
在 Redis 中,每一个 Key 都可以称之为一个对象,Redis 包含了这个 Key 的类型,value 的内存地址,LRU 淘汰时间,引用计数等
1 | struct RedisObject { |
从细节上来说,锁分为 乐观锁、悲观锁
乐观锁适用于读多写少的场景,一般是通过 CAS 进行操作,因为不用加锁,所以性能上比悲观锁优秀太多
悲观锁适用于写多读少的场景,性能开销比较大。
LockSupport 是一个用于线程阻塞或者唤醒的类,位于 rt.jar,主要是通过 Unsafe 类来进行操作
该类的方法都是静态方法,最常使用的方法是 void park(Object blocker) 和 void unpark(Thread thread)
是AQS操作的基础类,阻塞线程的时候不需要加锁,比较方便
下面主要介绍这两种方法:
在 jackson 将字符串转为对象的时候,如果是不带有范型的数据类,那么在 strig 转 obj 的时候不会出现什么问题,如果你的对象带有范型的话,那么就需要注意了,稍不注意就会抛出如下异常
java.util.LinkedHashMap cannot be cast to XX
出现该原因的原因在于 jackson 转换对象的时候,如果没有识别到原始类型,会默认将其转为 LinkedHashMap,后续一旦使用该类,就会抛出上述错误
demo如下:
如果你是使用如下方法进行 string 转 object,那么范型会被映射称为 LinkedHashMap
1 | public <T> T readValue(String content, Class<T> valueType) |
在了解这部分之前,你需要知道 Spring 都是通过 DispatcherServlet 来处理和分发请求的,如果不知道的话也不会影响到本文的阅读
在开启内容协商之后,URL 肯定是会变的,例如之前是 a/b,开启后则变成为 a/b.json 或者 a/b.xml
那么 Spring 首先第一步就需要解决如何将这个 url 映射到正确的 Controller 上的呢?
随着业务系统的成熟,如果你的项目正好是公司的中台战略之一,但是下游系统的接收方式不统一,这一种情况在一些老的公司系统架构总经常出现,如果下游系统不方便兼容,那么就需要中台系统对外提供各种不同格式返回报文
简单说就是服务提供方根据客户端所支持的格式来返回对应的报文,在 Spring 中,REST API 基本上都是以 json 格式进行返回,而如果需要一个接口即支持 json,又支持其他格式,开发和维护多套代码显然是不合理的,而 Spring 又恰好提供了该功能,那便是ContentNegotiation
在 Spring 中,决定一个数据是以 json、xml 还是 html 的方式返回有三种方式,分别如下: