java性能调优笔记

缓冲

缓冲(Buffer)通过对数据进行暂存,然后批量进行传输或者操作,多采用顺序方式,来缓解不同设备之间次数频繁但速度缓慢的随机读写。

从宏观上来说,JVM 的堆就是一个大的缓冲区,代码不停地在堆空间中生产对象,而垃圾回收器进程则在背后默默地进行垃圾回收。

优点在于:

  • 缓冲双方能各自保持自己的操作节奏,操作处理顺序也不会打乱,可以 one by one 顺序进行;

  • 以批量的方式处理,减少网络交互和繁重的 I/O 操作,从而减少性能损耗;

  • 优化用户体验,比如常见的音频/视频缓冲加载,通过提前缓冲数据,达到流畅的播放效果

缓冲区优化思路

缓冲通常配合异步编程。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jaf4vKVq-1605251095378)(https://s0.lgstatic.com/i/image/M00/3A/1A/Ciqc1F8hIuqATvhSAAB9F5pMiOE699.png)]

  • 同步

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YJlpmaYV-1605251095379)(https://s0.lgstatic.com/i/image/M00/3A/25/CgqCHl8hIvuAILAKAABaDCSPRRw546.png)]

  • 异步

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CS7xVGph-1605251095381)(https://s0.lgstatic.com/i/image/M00/3A/25/CgqCHl8hIwaAQl3SAACaljNt5Fs553.png)]

缓存

缓存的优化效果是非常好的,它既可以让原本载入非常缓慢的页面,瞬间秒开,也能让本是压力山大的数据库,瞬间清闲下来。缓存,本质上是为了协调两个速度差异非常大的组件。

缓存一致性

对于一个缓存项来说,常用的操作有四个:写入、更新、读取、删除。

  • 写入:缓存和数据库是两个不同的组件,只要涉及双写,就存在只有一个写成功的可能性,造成数据不一致。

  • 更新:更新的情况类似,需要更新两个不同的组件。

  • 读取:读取要保证从缓存中读到的信息是最新的,是和数据库中的是一致的。

  • 删除:当删除数据库记录的时候,如何把缓存中的数据也删掉?

推荐使用触发式的缓存一致性方式,使用懒加载的方式,可以让缓存的同步变得非常简单:

  • 当读取缓存的时候,如果缓存里没有相关数据,则执行相关的业务逻辑,构造缓存数据存入到缓存系统;

  • 当与缓存项相关的资源有变动,则先删除相应的缓存项,然后再对资源进行更新,这个时候,即使是资源更新失败,也是没有问题的。

但这样还是有问题。

上面提到的缓存删除动作,和数据库的更新动作,明显是不在一个事务里的。如果一个请求删除了缓存,同时有另外一个请求到来,此时发现没有相关的缓存项,就从数据库里加载了一份到缓存系统。接下来,数据库的更新操作也完成了,此时数据库的内容和缓存里的内容,就产生了不一致。

下面这张图,直观地解释了这种不一致的情况,此时,缓存读取 B 操作以及之后的读取操作,都会读到错误的缓存值。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B2PJ0nrO-1605251095383)(https://s0.lgstatic.com/i/image/M00/3D/B0/CgqCHl8qa5-AWDbqAACK1Itu_Wc954.png)]

可以使用分布式锁来解决这个问题,将缓存操作和数据库删除操作,与其他的缓存读操作,使用锁进行资源隔离即可。一般来说,读操作是不需要加锁的,它会在遇到锁的时候,重试等待,直到超时。

池化对象

池化技术——使用一个虚拟的池子,将这些资源保存起来,当使用的时候,我们就从池子里快速获取一个即可。

对象池在进行初始化时,要指定三个主要的参数:

  1. maxTotal对象池中管理的对象上限

  2. maxIdle最大空闲数

  3. minIdle最小空闲数

其中maxTotal和业务线程有关,当业务线程想要获取对象时,会首先检测是否有空闲的对象。如果有,则返回一个;否则进入创建逻辑。此时,如果池中个数已经达到了最大值,就会创建失败,返回空对象。

对象在获取的时候,有一个非常重要的参数,那就是最大等待时间(maxWaitMillis),这个参数对应用方的性能影响是比较大的。该参数默认为 -1,表示永不超时,直到有对象空闲。

下面的场景,就可以考虑使用池化来增加系统性能:

  • 对象的创建或者销毁,需要耗费较多的系统资源;

  • 对象的创建或者销毁,耗时长,需要繁杂的操作和较长时间的等待;

  • 对象创建后,通过一些状态重置,可被反复使用。

枚举模式单例实现

public class EnumSingleton { 

    private EnumSingleton() { 
    } 

    // static块,jvm会保证instance只被调用一次
    public static EnumSingleton getInstance() { 
        return Holder.HOLDER.instance; 
    } 

    private enum Holder { 
        HOLDER; 

        private final EnumSingleton instance; 

        Holder() { 
            instance = new EnumSingleton(); 
        } 
    } 
} 

static块,jvm会保证instance只被调用一次。Java只有在Enum类第一次被引用时才会去加载,也能保证懒加载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值