专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

java性能优化实战如何用设计模式进行性能优化

  头条创作挑战赛
  代码的结构对应用的整体性能,有着重要的影响。结构优秀的代码,可以避免很多潜在的性能问题,在代码的扩展性上也有巨大的作用;结构清晰、层次分明的代码,也有助于帮你找到系统的瓶颈点,进行专项优化。
  设计模式就是对常用开发技巧进行的总结,它使得程序员之间交流问题,有了更专业、便捷的方式。比如,我们在《02理论分析:性能优化有章可循,谈谈常用的切入点》中提到,IO模块使用的是装饰器模式,你就能很容易想到IO模块的代码组织方式。
  事实上,大多数设计模式并不能增加程序的性能,它只是代码的一种组织方式。本课时,我们将一一举例讲解和性能相关的几个设计模式,包括代理模式、单例模式、享元模式、原型模式等。如何找到动态代理慢逻辑的原因?
  Spring广泛使用了代理模式,它使用CGLIB对Java的字节码进行了增强。在复杂的项目中,会有非常多的AOP代码,比如权限、日志等切面。在方便了编码的同时,AOP也给不熟悉项目代码的同学带来了很多困扰。
  下面我将分析一个使用arthas找到动态代理慢逻辑的具体原因,这种方式在复杂项目中,非常有效,你不需要熟悉项目的代码,就可以定位到性能瓶颈点。
  首先,我们创建一个最简单的Bean(代码见仓库)。ComponentpublicclassABean{publicvoidmethod(){System。out。println();}}
  然后,我们使用Aspect注解,完成切面的书写,在前置方法里,我们让线程sleep了1秒钟。AspectComponentpublicclassMyAspect{Pointcut(execution(com。github。xjjdog。spring。ABean。(。。))))publicvoidpointcut(){}Before(pointcut())publicvoidbefore(){System。out。println(before);try{Thread。sleep(TimeUnit。SECONDS。toMillis(1));}catch(InterruptedExceptione){thrownewIllegalStateException();}}}
  创建一个Controller,当访问aop链接时,将会输出Bean的类名称,以及它的耗时。ControllerpublicclassAopController{AutowiredprivateABeanaBean;ResponseBodyGetMapping(aop)publicStringaop(){longbeginSystem。currentTimeMillis();aBean。method();longcostSystem。currentTimeMillis()begin;StringclsaBean。getClass()。toString();returnclscost;}}
  执行结果如下,可以看到AOP代理已经生效,内存里的Bean对象,已经变成了EnhancerBySpringCGLIB类型,调用方法method,耗时达到了1023ms。classcom。github。xjjdog。spring。ABeanEnhancerBySpringCGLIBa5d915351023
  下面使用arthas分析这个执行过程,找出耗时最高的AOP方法。启动arthas后,可以从列表中看到我们的应用程序,在这里,输入2进入分析界面。
  在终端输入trace命令,然后访问aop接口,终端将打印出一些debug信息,可以发现耗时操作就是Spring的代理类。tracecom。github。xjjdog。spring。ABeanmethod
  代理模式
  代理模式(Proxy)可以通过一个代理类,来控制对一个对象的访问。
  Java中实现动态代理主要有两种模式:一种是使用JDK,另外一种是使用CGLib。其中,JDK方式是面向接口的,主要的相关类是InvocationHandler和Proxy;CGLib可以代理普通类,主要的相关类是MethodInterceptor和Enhancer。
  这个知识点面试频率非常高,仓库中有这两个实现的完整代码,这里就不贴出来了。
  下面是JDK方式和CGLib方式代理速度的JMH测试结果:BenchmarkModeCntScoreErrorUnitsProxyBenchmark。cglibthrpt1078499。5801771。148opsmsProxyBenchmark。jdkthrpt1088948。858814。360opsms
  我现在用的JDK版本是1。8,可以看到,CGLib的速度并没有传得那么快(有传言高出10倍),相比较而言,它的速度甚至略有下降。我们再来看下代理的创建速度,结果如下所示。可以看到,在代理类初始化方面,JDK的吞吐量要高出CGLib一倍。BenchmarkModeCntScoreErrorUnitsProxyCreateBenchmark。cglibthrpt107281。4871339。779opsmsProxyCreateBenchmark。jdkthrpt1015612。467268。362opsms
  综上所述,JDK动态代理和CGLib代理的创建速度和执行速度,在新版本的Java中差别并不是很大,Spring选用了CGLib,主要是因为它能够代理普通类的缘故。单例模式
  Spring在创建组件的时候,可以通过scope注解指定它的作用域,用来标示这是一个prototype(多例)还是singleton(单例)。
  当指定为单例时(默认行为),在Spring容器中,组件有且只有一份,当你注入相关组件的时候,获取的组件实例也是同一份。
  如果是普通的单例类,我们通常将单例的构造方法设置成私有的,单例有懒汉加载和饿汉加载模式。
  了解JVM类加载机制的同学都知道,一个类从加载到初始化,要经历5个步骤:加载、验证、准备、解析、初始化。
  其中,static字段和static代码块,是属于类的,在类加载的初始化阶段就已经被执行。它在字节码中对应的是方法,属于类的(构造方法)。因为类的初始化只有一次,所以它就能够保证这个加载动作是线程安全的。
  根据以上原理,只要把单例的初始化动作,放在方法里,就能够实现饿汉模式。privatestaticSingletoninstacenewSingleton();
  饿汉模式在代码里用得很少,它会造成资源的浪费,生成很多可能永远不会用到的对象。而对象初始化就不一样了。通常,我们在new一个新对象的时候,都会调用它的构造方法,就是,用来初始化对象的属性。由于在同一时刻,多个线程可以同时调用函数,我们就需要使用synchronized关键字对生成过程进行同步。
  目前,公认的兼顾线程安全和效率的单例模式,就是doublecheck。很多面试官,会要求你手写,并分析doublecheck的原理。
  如上图,是doublecheck的关键代码,我们介绍一下四个关键点:第一次检查,当instance为null的时候,进入对象实例化逻辑,否则直接返回。加同步锁,这里是类锁。第二次检查才是关键。如果不加这次判空动作,可能会有多个线程进入同步代码块,进而生成多个实例。最后一个关键点是volatile关键字。在一些低版本的Java里,由于指令重排的缘故,可能会导致单例被new出来后,还没来得及执行构造函数,就被其他线程使用。这个关键字,可以阻止字节码指令的重排序,在写doublecheck代码时,习惯性会加上volatile。
  可以看到,doublecheck的写法繁杂,注意点很多,它现在其实是一种反模式,已经不推荐使用了,我也不推荐你用在自己的代码里。但它能够考察面试者对并发的理解,所以这个问题经常被问到。
  推荐使用enum实现懒加载的单例,代码片段如下:
  《EffectiveJava》这本书也同样推荐了该方式。publicclassEnumSingleton{privateEnumSingleton(){}publicstaticEnumSingletongetInstance(){returnHolder。HOLDER。instance;}privateenumHolder{HOLDER;privatefinalEnumSingletoninstance;Holder(){instancenewEnumSingleton();}}}享元模式
  享元模式(Flyweight)是难得的,专门针对性能优化的设计模式,它通过共享技术,最大限度地复用对象。享元模式一般会使用唯一的标识码进行判断,然后返回对应的对象,使用HashMap一类的集合存储非常合适。
  上面的描述,我们非常熟悉,因为在过去的一些课时中,我们就能看到很多享元模式的身影,比如《09案例分析:池化对象的应用场景》里的池化对象和《10案例分析:大对象复用的目标和注意点》里的对象复用等。
  设计模式对这我们平常的编码进行了抽象,从不同的角度去解释设计模式,都会找到设计思想的一些共通点。比如,单例模式就是享元模式的一种特殊情况,它通过共享单个实例,达到对象的复用。
  值得一提的是,同样的代码,不同的解释,会产生不同的效果。比如下面这段代码:MapString,StrategystrategysnewHashMap();strategys。put(a,newAStrategy());strategys。put(b,newBStrategy());
  如果我们从对象复用的角度来说,它就是享元模式;如果我们从对象的功能角度来说,那它就是策略模式。所以大家在讨论设计模式的时候,一定要注意上下文语境的这些差别。原型模式
  原型模式(Prototype)比较类似于复制粘贴的思想,它可以首先创建一个实例,然后通过这个实例进行新对象的创建。在Java中,最典型的就是Object类的clone方法。
  但编码中这个方法很少用,我们上面在代理模式提到的prototype,并不是通过clone实现的,而是使用了更复杂的反射技术。
  一个比较重要的原因就是clone如果只拷贝当前层次的对象,实现的只是浅拷贝。在现实情况下,对象往往会非常复杂,想要实现深拷贝的话,需要在clone方法里做大量的编码,远远不如调用new方法方便。
  实现深拷贝,还有序列化等手段,比如实现Serializable接口,或者把对象转化成JSON。
  所以,在现实情况下,原型模式变成了一种思想,而不是加快对象创建速度的工具。小结
  本课时,我们主要看了几个与性能相关的设计模式,包括一些高频的考点。我们了解到了Java实现动态代理的两种方式,以及他们的区别,在现版本的JVM中,性能差异并不大;我们还了解到单例模式的三种创建方式,并看了一个doublecheck的反例,平常编码中,推荐使用枚举去实现单例;最后,我们学习了享元模式和原型模式,它们概念性更强一些,并没有固定的编码模式。
  我们还顺便学习了arthas使用trace命令,寻找耗时代码块的方法,最终将问题定位到Spring的AOP功能模块里,而这种场景在复杂项目中经常发生,需要你特别注意。
  此外,在设计模式中,对性能帮助最大的是生产者消费者模式,比如异步消息、reactor模型等,而这一部分内容,我们将在之后的文章中进行讲解。

夜读真正在乎你的人行动,往往比语言更能说明问题。真正在乎你的人,是你的父母吗?不知你有没有发现,我们长大后,父母慢慢地变得像一个孩子,怕说错话,怕做错事,怕我们嫌弃,怕一不小心就惹怒了我们。我们的父时光嫣然,我在想你,深情未央,相思未忘秋日生活打卡季阵阵秋风吹过,又情不自禁地想起了你,捡起一片枫叶,又想起了从前,岁月中,因为有了你,才变得如此美丽,时光中,因为有你,才多了一份温柔。时光嫣然,我在想你,深情未央,相永生之罪天空落下乌鸦的零星片羽,翅膀划过天空的边缘,太阳又一次接管大地。但此刻,我坐在只有一处小窗的审讯室里,扯了扯手上的皮质手套。在女人不可置信的目光中,我与她沉默对视。她似乎还没太搞清如果遇到这样的女人,请你珍惜刚开始的时候你会觉得很烦,时间长了,你就习惯了,细细品来,你就甜蜜了如果你遇到这样的女人她把你当成她的全部,时时刻刻都缠着你,和你寸步不离,形影不分,把你的一举一动都放在眼里,她会欲望是心中之贼忙字中,藏了一个亡字,人们忙于欲望,殊不知过度的欲望是以情感内耗追逐死亡。意识能级理论认为欲望让我们耗费大量的努力去达成我们的目标,去取得我们的回报。这也是一个易上瘾的能级,不知道吃饭时有这三个习惯的人,多半面善心黑,我劝你最好远离图源自网络侵权请联系删除一个人有着什么样的人品和教养,其实不需要历经大量的时间和考验来判断,有时只需要跟他吃一顿饭,心里大概就有数了。因为吃饭时的一些习惯,跟他平常生活的环境有关,人民日报每日金句摘抄1人类的梦想有多么伟大,历史的进程就有多么壮阔。2治国犹如栽树,本根不摇则枝叶茂荣。治国有常,而利民为本。3胸怀千秋伟业,恰是百年风华。4黄河落天走东海,万里写入胸怀间。5当高楼大原创喜庆二十大奋进新征程(诗十首)喜庆二十大奋进新征程(诗五首)喜庆党的二十大胜利召开曹宏英一hr碧水蓝天云彩悠,花香果硕满金秋。国开盛会家家乐,政暖民心处处歌。绿水潺潺泽大地,红旗猎猎耀神州。群英汇聚谋宏业,再建心若向阳,无惧悲伤常在午后,选阳光明媚晴好日子,抬头仰望那一片蔚蓝天空,深深呼吸清凉带着大自然气息的空气,让心瞬间变得简约,岁月匆匆,转眼之间人生已过半,纵然是年华向晚,心若向阳,无惧悲伤,也要拾一从你的全世界路过张嘉佳摘抄做菜跟写字一样。写字讲究语感,做菜讲究手感。手一抖,整坨盐掉到锅里,结果狗都咽不下去。有人用闹钟也掌握不了火候,而有人单凭感觉,就能刚刚好。一切技能最后都靠天赋,勤学苦练,只能变成还剩一半在北漂从年初开始,时光就彷佛坐上了机器,一溜烟就到了秋季。秋季意味着别离。那天凌晨便开始下雨,玻璃窗上的雨滴响了一夜。我已办完了离职,晨起就要收拾行李,而先生的衣物是不用收拾的,这次别离
没有太阳地球会怎样太阳,我们地球上所有生物赖以生存的能量来源,地球上一切生命活动所需要的能量都直接或者间接地来自它。假如太阳突然熄灭消失,我们的地球会怎么样,我们人类乃至一切生命物种又会怎么样呢?太国际最新研究发现迄今最古老章鱼化石距今3。3亿3。23亿年中新网北京3月9日电(记者孙自法)施普林格自然旗下学术期刊自然通讯最新发表一篇古生物学研究论文称,研究人员在美国新发现一个有10只手臂的章鱼化石,其年代距今约3。3亿3。23亿年。新说地球是如何从一个大火球变得宜居的耶鲁大学和加州理工学院的研究人员有了一个大胆的新理论,来解释地球是如何从一个燃烧的碳云笼罩的岩石球转变为一个能够维持生命的行星的。这一理论涵盖了地球最早的时候,涉及奇怪的岩石,它们地球上的第一次生命大爆炸在地表深处产生了影响寒武纪大爆发(大约在5。41亿年前)是生命和生物真正开始在地球上生存的时候。现在,新的研究揭示了生命的爆发是如何在地幔深处留下痕迹的。对科学家来说,它显示了地表和地表之下的相互联系宇宙中的冷知识你知道多少?玄幻小说里面的主角,是一个比一个牛逼。今天咱们就扒一扒这些能动不动就星际穿梭的,一拳打爆一个星系的高手们,身体到底有多么的强悍?就拿冥王星来说,冥王星表面的常年平均温度在220,这人类首次成功使用AI控制核聚变反应,人造太阳取得重要进展可控核聚变一直是人类梦寐以求的未来能源,近几十年来,世界各国在这方面都投入了巨大的资源。2022年2月16日,科学期刊Nature发表了一篇来自瑞士洛桑联邦理工学院与英国人工智能研1800万,6300万,1。17亿,NBA第一数据刷子,5年仍骗走3份高薪隐藏5年的刷子,直到现在才被很多人识破。随着尼克斯再度深陷泥潭,他们的管理层也终于意识到,围绕朱利叶斯兰德尔建队的决定,可能真是一个错误,但却又无可奈何,因为在几个月前,他们刚跟兰银河系大得让人绝望,而它只是拉尼亚凯亚超星系团中的一粒沙子古时候,由于人类的科技不够发达,所以古人一直都认为地球就是唯一的世界,由于当时人类的交通工具不够发达,很多人一辈子都走不出方圆百里的范围,不过随着人类科技的进步,人类发明了很多交通2022爆款水桶包推荐CHANEL牛仔水桶包YSL新款绝美LV这款超仙水桶包一直都是精品超夯入门款,不仅外型时髦好搭,容量更是实用耐装!近期大牌也推出许多新的款式。辣酱整理了8款精品水桶包送给大家!包括CHANELYSLCELINELVLOEWE等,三星遭到集体起诉承认GalaxyS22限制性能,每人索赔30万韩元?三星GalaxyS22系列发布以后,频繁出现发热掉帧卡顿续航不佳等现象,面对质疑官方承认存在故意限制性能问题。此举引发用户广泛不满,正在准备对三星提起集体诉讼,指控其违反广告法进行路易威登2022秋冬女装系列,致敬青春,复古与创新的幻想曲巴黎时装周进入尾声,也迎来了个人最期待的LouisVuitton2022秋冬女装秀场。LV女装艺术总监NicolasGhesquire重启女性启蒙的的旅程,再一次打动人心。将新与旧
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网