返回顶部
首页 > 资讯 > 精选 >Java中性能相关的设计模式有哪些
  • 709
分享到

Java中性能相关的设计模式有哪些

2023-07-02 00:07:14 709人浏览 薄情痞子
摘要

这篇文章主要介绍“Java中性能相关的设计模式有哪些”,在日常操作中,相信很多人在Java中性能相关的设计模式有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中性能相关的设计模式有哪些”的疑惑有所

这篇文章主要介绍“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 测试结果:

BenchmarkModeCntScoreErrorUnits
ProxyBenchmark.cglibthrpt1078499.580±1771.148ops/ms
ProxyBenchmark.jdkthrpt1088948.858±814.360ops/ms

我现在用的 JDK 版本是 1.8,可以看到,CGLib 的速度并没有传得那么快(有传言高出10 倍),相比较而言,它的速度甚至略有下降。
我们再来看下代理的创建速度,结果如下所示。可以看到,在代理类初始化方面,JDK 的吞吐量要高出 CGLib 一倍。

BenchmarkModeCntScoreErrorUnits
ProxyCreateBenchmark.cglibthrpt107281.487± 1339.779ops/ms
ProxyCreateBenchmark.jdkthrpt1015612.467± 268.362ops/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 的写法繁杂,注意点很多,它现在其实是一种反模式,已经不推荐使用了,我也不推荐你用在自己的代码里。但它能够考察面试者对并发的理解,所以这个问题经常被问到。

代码片段如下:

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中性能相关的设计模式有哪些”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: Java中性能相关的设计模式有哪些

本文链接: https://lsjlt.com/news/338718.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java中性能相关的设计模式有哪些
    这篇文章主要介绍“Java中性能相关的设计模式有哪些”,在日常操作中,相信很多人在Java中性能相关的设计模式有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中性能相关的设计模式有哪些”的疑惑有所...
    99+
    2023-07-02
  • java中有哪些设计模式
    java中有哪些设计模式?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Num1:单例模式基本概念:保证一个类仅有一个实例,并提供一个访问它的全局访问点。常见写法:饿汉式publ...
    99+
    2023-06-15
  • java DAO设计模式有哪些功能
    这篇文章主要讲解了“java DAO设计模式有哪些功能”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java DAO设计模式有哪些功能”吧!什么是DAO    DAO是D...
    99+
    2023-06-03
  • java的设计模式有哪些
    java的设计模式有:1.适配器模式;2.单例模式;3.工厂模式;4.策略模式;java的设计模式有以下几种适配器模式java中适配器模式的作用是将一个类的方法接口转换成客户希望的另外一个接口,从而解决接口之间不兼容的问题。单例模式java...
    99+
    2024-04-02
  • java设计模式有哪些
    设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 总体来说设计模式分为三大类23种:创建型模式,共五种:工厂方...
    99+
    2015-05-18
    java 设计模式
  • Java中Spring设计模式有哪些
    这篇文章主要为大家展示了“Java中Spring设计模式有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java中Spring设计模式有哪些”这篇文章吧。一、简单工厂模式又叫做静态工厂方法(...
    99+
    2023-06-02
  • Java中设计模式的原则有哪些
    本篇文章给大家分享的是有关Java中设计模式的原则有哪些,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Java中的设计模式与7大原则:一、创建型模式抽象工厂模式(Abstrac...
    99+
    2023-05-31
    java 设计模式 ava
  • Java中设计模式的面试题有哪些
    这篇文章将为大家详细讲解有关Java中设计模式的面试题有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。面试题1:面向对象程序设计(OOP)的六大原则分别有哪几个开闭原则(Open Close Prin...
    99+
    2023-06-20
  • Java常用的设计模式有哪些
    小编给大家分享一下Java常用的设计模式有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Java常用的五种设计模式:1、单例设计模式;2、工厂设计模式;3、代...
    99+
    2023-06-14
  • Java设计模式的原则有哪些
    本文小编为大家详细介绍“Java设计模式的原则有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java设计模式的原则有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。设计模式的六大原则:1、单一职责原则,...
    99+
    2023-07-04
  • java中mvc设计模式有哪些特点
    Java中MVC(Model-View-Controller)设计模式具有以下特点:1. 分离关注点:MVC模式将应用程序的不同方面...
    99+
    2023-10-10
    java MVC
  • java设计模式有哪些原则
    这篇文章将为大家详细讲解有关java设计模式有哪些原则,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。设计模式软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数...
    99+
    2023-06-20
  • Java常见设计模式有哪些
    这篇文章主要介绍Java常见设计模式有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、设计模式总述:1、什么是设计模式:设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证...
    99+
    2023-06-29
  • spring中的设计模式有哪些
    这期内容当中小编将会给大家带来有关spring中的设计模式有哪些,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。1、工厂模式,在各种BeanFactory以及ApplicationContext创建中都用到...
    99+
    2023-05-31
    spring
  • Node.js中有哪些设计模式
    这期内容当中小编将会给大家带来有关Node.js中有哪些设计模式,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。什么是设计模式?设计模式是用来解决一般的,普遍发生的问题,且...
    99+
    2024-04-02
  • Python中有哪些设计模式
    Python中有哪些设计模式,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。目前的功能可以增加功能块可以增加连接线可以移动功能块可以输出JSON格式将来的功能支持基本的演算功...
    99+
    2023-06-19
  • jQuery的设计模式有哪些
    这篇文章主要讲解了“jQuery的设计模式有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“jQuery的设计模式有哪些”吧!一、发布订阅模式var&nb...
    99+
    2024-04-02
  • javascript的设计模式有哪些
    javascript中的设计模式有:1.单例模式,将代码组织成逻辑单元的手段;2.工厂模式,解决实列化对象产生重复的问题;3.适配模式,解决接口不兼容产生的问题;4.策略模式,将算法的使用与实现分离;javascript中的设计模式有以下几...
    99+
    2024-04-02
  • spring的设计模式有哪些
    这篇文章主要讲解了“spring的设计模式有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“spring的设计模式有哪些”吧!1. 简单工厂又叫做静态工厂方法(StaticFactory ...
    99+
    2023-06-03
  • Node中exports有哪些设计模式
    本篇文章给大家分享的是有关Node中exports有哪些设计模式,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。首先我们需要先聊点基础的知识在N...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作