善用单例设计模式,代码性能提升300%。java代码如何运行?堆内存满了怎么办?如何使用单例模式优化系统性能?大家好,今天给大家分享一个写代码的设计模式,也就是我们最熟悉的单例设计模式。很多人可能听说过这种单例设计模式,甚至偷偷写过,但是今天我将告诉大家如何使用这种单例设计模式来极大地提高代码的性能。代码性能之间的关系,恐怕很多兄弟都没有认真研究过吧!首先我们来看看什么叫单例模式。我们通常如何创建对象。创建对象通常很容易。比如我们创建一个对外的web接口,然后在接口收到请求的时候创建一个对象。伪代码如下:@RestController("/user")publicclassController{privateUserServiceuserService;@RequestMapping("/create")publicResponsecreate(CreateUserRequestrequest){Useruser=newUser(request);UserServiceuserService=newUserService();userService.add(用户);返回Response.success();}}上面的代码极其简单,假设你有一个Controller,对外提供http接口,然后每次通过浏览器请求发送一个createuser。即对于url/user/create的请求,发送一个CreateUserRequest请求参数,代码会使用new关键字创建一个User对象。然后通过new关键字创建一个UserService组件,然后将User对象交给UserService组件来将用户数据插入到数据库中。这段代码,懂java的人基本都能看懂。但是这里有一个问题。您知道每次处理请求时这段代码会做什么吗?其实最关键的一点是,每次请求时,都会在内存中创建一个User对象和一个UserService。对象,这些对象是如何创建的?java代码如何运行?接下来我要揭秘这段代码运行的底层原理。首先,当我们启动一个Java程序的时候,肯定会启动一个JVM进程。比如上面的代码,你可以通过SpringBoot等框架从main方法启动,也可以打包放到Tomcat中运行。如果直接运行main方法启动,那么会直接启动一个JVM进程。如果把代码打包运行在Tomcat中,那么Tomcat本身就是一个JVM进程。如下图所示:然后,其实你启动的JVM进程会把你写的代码加载到内存中,然后运行你写的代码。当你的代码运行起来之后,它就可以做你想让它做的事情了,比如接收浏览器发送的http请求,然后创建一些对象,将它们插入到数据库中等等。如下图所示:那么这个时候,有一个非常关键的点,就是你的代码运行的时候,用newUser()和newUserService()创建的对象抛到哪里去了?很简单,你的JVM进程是有一块属于自己的内存区域可以使用的,只有他才能使用。该区域称为堆内存。这好比我们在自己的房子里建一个小别墅,弄个院子,可以种花种草。别人总不能在你院子里种黄瓜、种大蒜吧?如下图所示:那么,我们上面写的那段代码,大家注意,每次收到请求,都会创建一个User对象和一个UserService对象,对吧?那么,随着你不断的发送请求,我们的代码是不是会一直创建对象,一直创建对象,那么在我们的堆内存中,对象会不会越来越多呢?如下图:堆内存满了怎么办?那我问大家一个问题,堆内存就是一块内存空间,他能不能无限往里面放对象呢?当然不是,当你的对象越来越多,多了的时候,这块内存空间就会被给满了,满了之后就放不下新的对象了。这个时候怎么办?它会触发一个垃圾回收动作,即JVM进程会自己偷偷开一个垃圾回收线程,这个线程会盯着我们。堆内存感觉快满了,清理了里面的一些对象。这称为垃圾收集。如下图所示:但是每次垃圾回收都有一个问题。因为它需要清理一些对象,所以在清理对象的时候经常会阻止你创建新的对象。否则,就和你妈妈打扫你的房间一样。他们清理垃圾的时候,你还在吃东西,把垃圾扔在地上。你妈妈不打你才怪,对吧?所以当垃圾被回收时,会让JVM进程停止工作,不要创建新的对象。如下图所示:那么在垃圾回收的时候JVM进程停止运行的这段时间,会不会造成一个问题,就是没有人会去处理你的用户发来的请求。没错,这时候用户会觉得每次发送请求都卡了,一直卡着没有返回。此时,系统性能处于很差的状态。如下图所示:单例模式如何优化系统性能?那么这个时候问题就来了。回到本文正文,单例模式如何优化系统性能?其实对于上面的问题,很多小伙伴可能已经发现了,如果要优化系统性能,一个关键点就是创建尽可能少的对象,避免频繁填充堆内存,这样也可以避免频繁垃圾回收和频繁的JVM进程停顿,进而避免频繁的卡顿和无响应的系统请求。那么如何创建更少的对象呢?单例模式是一个很好的方式。对于我们来说,其实可以让UserService对象只创建一次,而不是每次请求的时候都重复创建。让一个对象创建一次,就是单例模式。单例模式的写法有很多种,其中一种是:@RestController("/user")publicclassController{privateUserServiceuserService;@RequestMapping("/create")publicResponsecreate(CreateUserRequestrequest){Useruser=newUser(request);UserServiceuserService=UserSerivce.getInstance();userService.add(用户);返回Response.success();}}publicclassUserService{privateUserService(){}privatestaticclassSingleton{staticUserServiceuserService=newUserService();}publicstaticUserServicegetInstance(){returnSingleton.userService;}}可以看到上面的代码,我们在UserService中定义了一个私有化的static内部类Singleton,在Singleton中定义了一个静态变量UserService对象。这样的话,Singleton类只会被加载一次,只有在加载类的时候才会实例化一个静态变量UserService对象,并且每次都会通过getInstance()方法直接获取唯一的对象,不会被重复创建对象。这是单例模式的一种写法,也是企业开发中最常用的一种写法。使用单例模式后,我们可以大大减少创建对象的数量,避免频繁的堆内存填满,以及频繁的垃圾回收。频繁的JVM进程停顿会影响请求性能,这往往可以帮助我们更好的提升系统性能。
