成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網
最全最豐富的資訊網站

一起來聊聊與Java中性能相關的設計模式

本篇文章給大家帶來了關于java的相關知識,其中主要介紹了關于與性能相關的設計模式,大多數設計模式只是代碼的一種組織方式,只有部分設計模式與性能相關,包括代理模式、單例模式、享元模式、原型模式等,下面一起來看一下,希望對大家有幫助。

一起來聊聊與Java中性能相關的設計模式

推薦學習:《java視頻教程》

代碼的結構對應用的整體性能,有著重要的影響。結構優秀的代碼,可以避免很多潛在的性能問題,在代碼的擴展性上也有巨大的作用;結構清晰、層次分明的代碼,也有助于幫你找到系統的瓶頸點,進行專項優化。

設計模式就是對常用開發技巧進行的總結,它使得程序員之間交流問題,有了更專業、便捷的方式。

事實上,大多數設計模式并不能增加程序的性能,它只是代碼的一種組織方式。本文,我們將一一舉例講解和性能相關的幾個設計模式,包括代理模式、單例模式、享元模式、原型模式等。

代理模式

代理模式(Proxy)可以通過一個代理類,來控制對一個對象的訪問。

Java 中實現動態代理主要有兩種模式:一種是使用 JDK,另外一種是使用 CGLib。 其中,JDK 方式是面向接口的,主要的相關類是 InvocationHandler 和 Proxy;CGLib 可以代理普通類,主要的相關類是 MethodInterceptor 和 Enhancer。

這個知識點面試頻率非常高。

CGLib

package cn.wja.proxy.cglibproxy;import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class CglibInterceptor implements MethodInterceptor {     @Override     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {         return methodProxy.invokeSuper(o, objects);     }}
package cn.wja.proxy.cglibproxy;import cn.wja.proxy.jdkproxy.Target;import cn.wja.proxy.jdkproxy.TargetImpl;import org.springframework.cglib.proxy.Enhancer;public class CglibFactory {      public static Target newInstance() {         Enhancer enhancer = new Enhancer();         enhancer.setSuperclass(TargetImpl.class);         enhancer.setCallback(new CglibInterceptor());         return (Target) enhancer.create();     }      public static void main(String[] args) {         Target target = newInstance();         System.out.println(target.targetMetod(4));     }}

JDK

package cn.wja.proxy.jdkproxy;public interface Target {     int targetMethod(int i);}
package cn.wja.proxy.jdkproxy;public class TargetImpl implements Target {     @Override     public int targetMethod(int i) {         return i * i;     }}
package cn.wja.proxy.jdkproxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class JdkInvocationHandler implements InvocationHandler {     private Target target;      public JdkInvocationHandler(Target target) {         this.target = target;     }      @Override     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {         //before         Object object = method.invoke(target, args);         //after         return object;     }}
package cn.wja.proxy.jdkproxy;import java.lang.reflect.Proxy;public class JdkFactory {     public static Target newInstance(Target target) {         Object object = Proxy.newProxyInstance(JdkInvocationHandler.class.getClassLoader(),                 new Class<?>[]{Target.class},                 new JdkInvocationHandler(target));         return Target.class.cast(object);     }      public static void main(String[] args) {         Target t = new TargetImpl();         Target target = newInstance(t);         System.out.println(target.targetMethod(4));     }}

下面是 JDK 方式和 CGLib 方式代理速度的 JMH 測試結果:

Benchmark Mode Cnt Score Error Units
ProxyBenchmark.cglib thrpt 10 78499.580 ±1771.148 ops/ms
ProxyBenchmark.jdk thrpt 10 88948.858 ±814.360 ops/ms

我現在用的 JDK 版本是 1.8,可以看到,CGLib 的速度并沒有傳得那么快(有傳言高出10 倍),相比較而言,它的速度甚至略有下降。
我們再來看下代理的創建速度,結果如下所示。可以看到,在代理類初始化方面,JDK 的吞吐量要高出 CGLib 一倍。

Benchmark Mode Cnt Score Error Units
ProxyCreateBenchmark.cglib thrpt 10 7281.487 ± 1339.779 ops/ms
ProxyCreateBenchmark.jdk thrpt 10 15612.467 ± 268.362 ops/ms

Spring動態代理

Spring 廣泛使用了代理模式,它使用 CGLIB 對 Java 的字節碼進行了增強。在復雜的項目中,會有非常多的 AOP 代碼,比如權限、日志等切面。在方便了編碼的同時,AOP 也給不熟悉項目代碼的同學帶來了很多困擾。

下面我將分析一個使用 arthas 找到動態代理慢邏輯的具體原因,這種方式在復雜項目中,非常有效,你不需要熟悉項目的代碼,就可以定位到性能瓶頸點。

首先,我們創建一個最簡單的 Bean。

package cn.wja.spring;import org.springframework.stereotype.Component;@Componentpublic class ABean {     public void method() {         System.out.println("****ABean method*******************");     }}

然后,我們使用 Aspect 注解,完成切面的書寫,在前置方法里,我們讓線程 sleep 了 1 秒鐘。

package cn.wja.spring;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;@Aspect@Componentpublic class MyAspect {     @Pointcut("execution(* cn.wja.spring.ABean.*(..)))")     public void pointcut() {     }      @Before("pointcut()")     public void before() {         System.out.println("before");         try {             Thread.sleep(TimeUnit.SECONDS.toMillis(1));         } catch (InterruptedException e) {             throw new IllegalStateException();         }     }}

創建一個啟動類,當訪問 /aop 鏈接時,將會輸出 Bean 的類名稱,以及它的耗時。

package cn.wja.spring;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.ResponseBody;@SpringBootApplication@EnableAsync@Controllerpublic class App {     public static void main(String[] args) {         SpringApplication.run(App.class, args);     }     @Autowired     private ABean aBean;      @ResponseBody     @GetMapping("/aop")     public String aop() {         long begin = System.currentTimeMillis();         aBean.method();         long cost = System.currentTimeMillis() - begin;         String cls = aBean.getClass().toString();         return cls + " | " + cost;     }}

訪問結果如下,可以看到 AOP 代理已經生效,內存里的 Bean 對象,已經變成了EnhancerBySpringCGLIB 類型,調用方法 method,耗時達到了1005ms。

一起來聊聊與Java中性能相關的設計模式
下面使用 arthas 分析這個執行過程,找出耗時最高的 AOP 方法。啟動 arthas 后,可以從列表中看到我們的應用程序,在這里,輸入 1 進入分析界面。

一起來聊聊與Java中性能相關的設計模式
在終端輸入 trace 命令,然后訪問 /aop 接口,終端將打印出一些 debug 信息,可以發現耗時操作就是 Spring 的代理類。

trace cn.wja.spring.ABean method

一起來聊聊與Java中性能相關的設計模式

單例模式

Spring 在創建組件的時候,可以通過 scope 注解指定它的作用域,用來標示這是一個prototype(多例)還是 singleton(單例)。

當指定為單例時(默認行為),在 Spring 容器中,組件有且只有一份,當你注入相關組件的時候,獲取的組件實例也是同一份。

如果是普通的單例類,我們通常將單例的構造方法設置成私有的,單例有懶漢加載和餓漢加載模式。

餓漢模式

了解 JVM 類加載機制的同學都知道,一個類從加載到初始化,要經歷 5 個步驟:加載、驗證、準備、解析、初始化。
一起來聊聊與Java中性能相關的設計模式
其中,static 字段和 static 代碼塊,是屬于類的,在類加載的初始化階段就已經被執行。它在字節碼中對應的是 方法,屬于類的(構造方法)。因為類的初始化只有一次,所以它就能夠保證這個加載動作是線程安全的。

根據以上原理,只要把單例的初始化動作,放在方法里,就能夠實現餓漢模式。

private static Singleton instace = new Singleton();

理論上來說,餓漢模式它會造成資源的浪費,可能生成一些永遠不會用到的對象,因此很多教程不建議用。但實際上來說,這存粹是脫褲子放屁,如果你真的永遠用不到這個對象,你為何要創建這個類,寫一個單例模式? 我覺得對于普通項目來說,餓漢模式就完全足夠了。

飽漢模式

而對象初始化就不一樣了。通常,我們在 new 一個新對象的時候,都會調用它的構造方法,就是,用來初始化對象的屬性。由于在同一時刻,多個線程可以同時調用函數,我們就需要使用 synchronized 關鍵字對生成過程進行同步。

package cn.wja.singleton;public class DoubleCheckSingleton {     private volatile static DoubleCheckSingleton instance = null;     private DoubleCheckSingleton() {     }      public static DoubleCheckSingleton getInstance() {         if (null == instance) {             synchronized (DoubleCheckSingleton.class) {                 if (null == instance) {                     instance = new DoubleCheckSingleton();                 }             }         }         return instance;     }}

如上面是 double check 的關鍵代碼,我們介紹一下四個關鍵點:

  • 第一次檢查,當 instance 為 null 的時候,進入對象實例化邏輯,否則直接返回。
  • 加同步鎖,這里是類鎖。
  • 第二次檢查才是關鍵。如果不加這次判空動作,可能會有多個線程進入同步代碼塊,進而生成多個實例。
  • 最后一個關鍵點是 volatile 關鍵字。在一些低版本的 Java 里,由于指令重排的緣故,可能會導致單例被 new 出來后,還沒來得及執行構造函數,就被其他線程使用。 這個關鍵字,可以阻止字節碼指令的重排序,在寫 double check 代碼時,習慣性會加上 volatile。

可以看到,double check 的寫法繁雜,注意點很多,它現在其實是一種反模式,已經不推薦使用了,我也不推薦你用在自己的代碼里。但它能夠考察面試者對并發的理解,所以這個問題經常被問到。

推薦使用 enum 實現懶加載的單例,《Effective Java》這本書也同樣推薦了該方式。代碼片段如下:

package cn.wja.singleton;public class EnumSingleton {     private EnumSingleton() {     }      public static EnumSingleton getInstance() {         return Holder.HOLDER.instance;     }      private enum Holder {         HOLDER;         private final EnumSingleton instance;         Holder() {             instance = new EnumSingleton();         }     }      public static void main(String[] args) {         System.out.println(getInstance());     }}

如果要借助spring框架那就更簡單了:

package cn.wja.singleton;import org.springframework.context.annotation.Scope;import org.springframework.stereotype.Component;@Component@Scope("singleton")public class SpringBean {     //具體內容}

享元模式

享元模式(Flyweight)專門針對性能優化的設計模式,它通過共享技術,最大限度地復用對象。享元模式一般會使用唯一的標識碼進行判斷,然后返回對應的對象,使用 HashMap 一類的集合存儲非常合適。

上面的描述,我們非常熟悉,因為本專欄的之前的博文中,我們就能看到很多享元模式的身影,比如博文 淺談Java中的池化技術 里的池化對象和博文 如何處理Java中的大對象 里的對象復用等。

案例:Integer

在Java中,我們常見的Integer,為了提升效率,在創建[1,127]范圍內的對象時也用了享元模式。通過下面的測試代碼可以驗證。

@Testpublic void myTest() throws Exception{     Integer a=1;     Integer b=1;     System.out.println(a == b ? "a b同一個對象" : "a b不是同一個對象");      Integer c=128;     Integer d=128;     System.out.println(c == d ? "c d同一個對象" : "c d不是同一個對象");}

一起來聊聊與Java中性能相關的設計模式

多視角看問題

設計模式對這我們平常的編碼進行了抽象,從不同的角度去解釋設計模式,都會找到設計思想的一些共通點。比如,單例模式就是享元模式的一種特殊情況,它通過共享單個實例,達到對象的復用。

值得一提的是,同樣的代碼,不同的解釋,會產生不同的效果。比如下面這段代碼:

Map<String,Strategy> strategys = new HashMap<>(); strategys.put("a",new AStrategy()); strategys.put("b",new BStrategy());

如果我們從對象復用的角度來說,它就是享元模式;如果我們從對象的功能角度來說,那它就是策略模式。所以大家在討論設計模式的時候,一定要注意上下文語境的這些差別。

原型模式

原型模式(Prototype)比較類似于復制粘貼的思想,它可以首先創建一個實例,然后通過這個實例進行新對象的創建。在 Java 中,最典型的就是 Object 類的 clone 方法。

但編碼中這個方法很少用,我們上面在代理模式提到的 prototype,并不是通過 clone 實現的,而是使用了更復雜的反射技術。

一個比較重要的原因就是 clone 如果只拷貝當前層次的對象,實現的只是淺拷貝。在現實情況下,對象往往會非常復雜,想要實現深拷貝的話,需要在 clone 方法里做大量的編碼,遠遠不如調用 new 方法方便。

實現深拷貝,還有序列化等手段,比如實現 Serializable 接口,或者把對象轉化成 JSON。

所以,在現實情況下,原型模式變成了一種思想,而不是加快對象創建速度的工具。

推薦學習:《java視頻教程》

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
日韩无码视频一区| 我和亲妺妺乱的性视频| 少妇泬出白浆18P| 小SB是不是想被C了| 亚洲国产精品久久久久秋霞影院| 亚洲中国最大AV网站| 2021精品亚洲中文字幕| FREEXXXXHD国语对白| 大象成品W灬源码1| 国产欧美精品一区二区三区-老狼| 精品成人毛片一区二区| 免费无码AV一区二区波多野结衣| 人妻被黑人与白人巨大中出| 天堂中文最新版在线中文| 亚洲AV不卡无码国产| 一本到无码AV专区无码| OLDMACDONALD老人大包| 国产92刮伦脏话对白| 黑鬼吊太大少妇尖叫| 毛片无码免费无码播放| 日本人真人姓交大视频| 无套中出丰满人妻无码| 一本大道大臿蕉无码视频| www亚洲一级AV仑片| 国产精品无码专区| 久久天天躁狠狠躁夜夜AV不卡| 欧美性猛交aaaa乱大交| 西西人体艺术摄影| 制服 丝袜 亚洲 中文 综合| 成人无码无遮挡很H在线播放| 国产亚洲精品自在久久VR| 美国ZOOM人与ZOOM| 少妇BBW搡BBBB搡BBBB| 亚洲欧洲日产国码无码AV一| ているの天堂资源WWW| 国产无遮挡又黄又爽不要VIP软| 久久躁狠狠躁夜夜AV| 日日摸夜夜添夜夜添AV| 亚洲国产五月综合网| おやすみせくよ晚安免费影院| 国产私人尤物无码不卡| 免费A级毛片波多野结衣| 调教小奴高潮惩罚PLAY道具| 一边做饭一边暴躁怎么办 | 精东传媒VS天美传媒在线老牛| 欧美成人精品高清在线观看| 无码日韩人妻精品久久| 18亚洲AV无码成人国产| 国产精品网站在线观看免费传媒 | 五月天天爽天天狠久久久综合| 再深点灬舒服灬太大了下载| 国产AV一区二区精品凹凸| 黎朔缠着腰不让他退出微博| 天天摸夜夜添狠狠添高潮出水| 又粗又大又爽又舒服日产| 高雅人妻被迫沦为玩物| 麻豆影视视频高清在线观看| 色老板在线永久免费视频| 日本精品一区二区三区在线视频| 亚洲AV无码国产精品久久不卡| 99久久99久久精品国产片| 国产内射老熟女AAAA∵| 欧美乱妇高清无乱码在线观看| 亚洲AV素人乱码| 波多野结衣高清一区二区三区| 精品无码一区二区三区| 少妇CHINA中国人妻VIDE| 杂交BUCSM人类SSBA| 国产精品美女久久久久AV福利| 妺妺和我裸睡玩我下春雨医生| 亚洲 欧美 变态 另类 综合| FREEZEFRAME丰满少妇| 精品人在线二线三线区别| 少妇饥渴偷公乱第一章全文| 18成禁人视频免费网站| 狠狠综合久久久久尤物丿| 日韩内射美女人妻一区二区三区| 一边做一边潮喷18P| 国产天堂亚洲国产碰碰| 日韩精品无码专区免费视频| 中文字幕乱偷无码AV先锋| 韩国电影理伦片完整| 色综合久久综合中文综合网| 97性无码区免费| 久久99精品久久久久久不卡| 无码专区6080YY电影| 菠萝视频免费最新在线观看| 美美哒免费高清影院| 亚洲精品狼友在线播放| 国产精品免费高清在线观看| 人妻丰满熟妇AV无码区免| 亚洲综合色区另类AV| 皇上御花园HLH| 国产精品久久久久精品综合 | 91夜色精品偷窥熟女精品网站 | 国产成人A视频高清在线观看| 欧美猛少妇色XXXXⅩBBBB| 一区二区乱子伦在线播放| 日产精品99久久久久久| 亚洲国产丝袜精品一区| 国产乱子伦精品无码码专区| 日韩精品无码综合福利网| AV天堂永久资源网AV天堂| 免费A级毛片无码A∨蜜芽18禁| 亚洲色成人WWW永久在线观看| 国内精自线一二三四2021| 无码熟熟妇丰满人妻啪啪| 高清不卡亚洲日韩AV在线| 日本婷婷色色电影| www.comAV在线观看| 男同GAY片自慰AV网站| 长腿校花无力呻吟娇喘| 久久久亚洲熟妇熟女ⅩXXXHD| 亚洲精品无码不卡久久久久| 国外亚洲成AV人片在线观看| 香蕉97超级碰碰碰视频| 国产精品成人久久久久久久| 思思RE热免费精品视频66| 国产777涩在线 | 美洲| 少妇性XXXXXXXXX色野| 荡公乱妇HD在线播放BD| 色噜噜狠狠色综合久色AⅤ网黑| 超清纯白嫩大学生无码网站| 日本精品成人一区二区三区视频| 办公室撕开奶罩揉吮奶头在线观看| 欧美又粗又长XXXXBBBB疯| AV最新高清无码专区| 欧洲无码一区二区三区在线观看| AV无码AV在线A∨天堂毛片| 女人18片毛片60分钟完整版| ASS鲜嫩鲜嫩PICS| 欧美性极品少妇精品网站| 爆乳女教师 高清BD| 三个男人换着躁我一| 国产99视频精品免视看7| 挺进邻居人妻雪白的身体韩国电影 | 成人无码区免费A∨直播| 色综合久久精品亚洲国产消防 | 亚洲AV永久无码精品秋霞电影影| 狠狠躁夜夜躁青青草原软件| 亚洲嫩草AV永久无码精品天堂| 久久不见久久见WWW免费| 泳池里强摁做开腿呻吟| 拗女稀缺资源一区二区| А∨天堂一区一本到| 色欲AV浪潮AV蜜臀AⅤ| 国产精品VA无码一区二区| 亚洲Av无码一区二区三区大黄瓜 | 少妇被躁爽到高潮无码文| 国产精品成人VA在线观看| 亚洲AV无码一区二区三区大黄瓜 | VODAFONEWIFI暴力| 日日摸夜夜添夜夜添高潮喷水| 国产成人一区二区三区免费视频| 午夜亚洲AⅤ无码高潮片| 久久国产精品二国产精品| 中文字幕无码AV不卡一区| 人妻丰滿熟妇αV无码HD| 父母全家儿女大联欢第14集| 西西人体艺术图片| 久久久亚洲熟妇熟女ⅩXXXHD| 99久久国产综合精品女| 色鬼7777久久| 国自产拍亚洲免费视频| 一区二区三区欧美| 亲近相奷对白中文字幕| 国产成人69视频午夜福利在线观| 亚洲AV成人网站| 久久亚洲AV无码精品色午夜麻| FREEMOVIES性中国| 天天躁日日躁狠狠躁婷婷| 激情国产AV做激情国产爱| 中文文字幕文字幕亚洲色| 日本在线观看母与子| 国产熟妇人妻ⅩXXXX麻豆网址| 一本久久综合亚洲鲁鲁五月天| 欧洲女RAPPER潮水大豆| 国产精品久久久尹人香蕉| 亚洲熟妇无码一区二区三区导航 | 毛茸茸的撤尿正面BBW| 成 人 黄 色 视 频网址大全| 午夜亚洲AⅤ无码高潮片| 久久综合噜噜激激的五月天| 边做奶水边喷H高H共妻| 亚洲AV鲁丝一区二区三区| 免费观看添你到高潮视频| 高潮毛片无遮挡高清免费视频 | Y1111111少妇影院无码| 西西人体午夜视频无码| 蜜桃AV无码国产丝袜在线观看| 丰满少妇高潮惨叫久久久| 亚洲日韩丝袜熟女变态夜夜爽| 亲子乱AⅤ一区二区三区 | 国产精品VIDEOSSEX久久发布| 一本久道综合色婷婷五月| 三个人一起玩3Q详细经过| 久久国产乱子伦免费精品 | 精品一区二区三区东京热| 成人AV在线网站| 亚洲中文AⅤ中文字幕|