23种设计模式(1) java单例模式
作者:阿木侠 发布时间:2021-08-28 21:56:28
23种设计模式第四篇:java单例模式
定义:
单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。即一个类只有一个对象实例。
特点:
1、单例类只能有一个实例。
2、单例类必须自己自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例
单例模式的要点:
1、私有的构造方法
2、指向自己实例的私有静态引用
3、以自己实例为返回值的静态的公有的方法
单例模式根据实例化对象时机的不同分为两种:
一种是饿汉式单例,一种是懒汉式单例。
饿汉式单例在单例类被加载时候,就实例化一个对象交给自己的引用;而懒汉式在调用取得实例方法的时候才会实例化对象。
代码如下:
饿汉式单例
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return singleton;
}
}
懒汉式单例
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(singleton==null){
singleton = new Singleton();
}
return singleton;
}
}
单例模式还有一种比较常见的形式:双重锁的形式
public class Singleton{
private static volatile Singleton instance=null;
private Singleton(){
//do something
}
public static Singleton getInstance(){
if(instance==null){
synchronized(SingletonClass.class){
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
}
}
这个模式将同步内容下方到if内部,提高了执行的效率,不必每次获取对象时都进行同步,只有第一次才同步,创建了以后就没必要了。
这种模式中双重判断加同步的方式,比第一个例子中的效率大大提升,因为如果单层if判断,在服务器允许的情况下,假设有一百个线程,耗费的时间为100*(同步判断时间+if判断时间),而如果双重if判断,100的线程可以同时if判断,理论消耗的时间只有一个if判断的时间。
所以如果面对高并发的情况,而且采用的是懒汉模式,最好的选择就是双重判断加同步的方式。
单例模式的优点:
1、在内存中只有一个对象,节省内存空间。
2、避免频繁的创建销毁对象,可以提高性能。
3、避免对共享资源的多重占用。
4、可以全局访问。
单例模式的优点:
1、扩展困难,由于getInstance静态函数没有办法生成子类的实例。如果要拓展,只有重写那个类。
2、隐式使用引起类结构不清晰。
3、导致程序内存泄露的问题。
适用场景:
由于单例模式的以上优点,所以是编程中用的比较多的一种设计模式。以下为使用单例模式的场景:
1、需要频繁实例化然后销毁的对象。
2、创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
3、资源共享的情况下,避免由于资源操作时导致的性能或损耗等
4、控制资源的情况下,方便资源之间的互相通信。
单例模式注意事项:
只能使用单例类提供的方法得到单例对象,不要使用反射,否则将会实例化一个新对象。
不要做断开单例类对象与类中静态引用的危险操作。
多线程使用单例使用共享资源时,注意线程安全问题。
关于Java中单例模式的一些常见问题:
单例模式的对象长时间不用会被jvm垃圾收集器收集吗
除非人为地断开单例中静态引用到单例对象的联接,否则jvm垃圾收集器是不会回收单例对象的。
jvm卸载类的判定条件如下:
1,该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例。
2,加载该类的ClassLoader已经被回收。
3,该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。
只有三个条件都满足,jvm才会在垃圾收集的时候卸载类。显然,单例的类不满足条件一,因此单例类也不会被回收。
在一个jvm中会出现多个单例吗
在分布式系统、多个类加载器、以及序列化的的情况下,会产生多个单例,这一点是无庸置疑的。那么在同一个jvm中,会不会产生单例呢?使用单例提供的getInstance()方法只能得到同一个单例,除非是使用反射方式,将会得到新的单例。
代码如下:
Class c = Class.forName(Singleton.class.getName());
Constructor ct = c.getDeclaredConstructor();
ct.setAccessible(true);
Singleton singleton = (Singleton)ct.newInstance();
这样,每次运行都会产生新的单例对象。所以运用单例模式时,一定注意不要使用反射产生新的单例对象。
在getInstance()方法上同步有优势还是仅同步必要的块更优优势?
因为锁定仅仅在创建实例时才有意义,然后其他时候实例仅仅是只读访问的,因此只同步必要的块的性能更优,并且是更好的选择。
缺点:只有在第一次调用的时候,才会出现生成2个对象,才必须要求同步。而一旦singleton 不为null,系统依旧花费同步锁开销,有点得不偿失。
单例类可以被继承吗
根据单例实例构造的时机和方式不同,单例模式还可以分成几种。但对于这种通过私有化构造函数,静态方法提供实例的单例类而言,是不支持继承的。
这种模式的单例实现要求每个具体的单例类自身来维护单例实例和限制多个实例的生成。但可以采用另外一种实现单例的思路:登记式单例,来使得单例对继承开放。
转自:java知音
来源:http://www.jb51.net/article/127870.htm


猜你喜欢
- 本文实例讲述了C#4.0新特性的协变与逆变,有助于大家进一步掌握C#4.0程序设计。具体分析如下:一、C#3.0以前的协变与逆变如果你是第一
- 本文列举了我在周围同事的Java代码中看到的一些比较典型的错误。显然,静态代码分析(我们团队用的是qulice)不可能发现所有的问题,这也是
- 数据层测试事务回滚pom.xml导入对应的一些坐标,mysql,Mp,等<dependency> &
- \r与\n到底有何区别,编码的时候又应该如何使用,我们下面来了解一下。区别:\r:全称:carriage return (carriage是
- 本文实例为大家分享了java实现捕鱼达人游戏的具体代码,供大家参考,具体内容如下效果图如下:源代码分享:测试类:package game;i
- 一:前言:最近支付后台登录一段时间后如果没有任何操作,总是需要重新登录才可以继续访问页面,出现这个问题的原因就是session超时,debu
- 关于注入数据说明1.不通过配置文件注入数据通过@Value将外部的值动态注入到Bean中,使用的情况有:注入普通字符串注入操作系统属性注入表
- CountDownLatch简介CountDownLatch顾名思义,count + down + latch = 计数 + 减 + 门闩(
- 本文实例为大家分享了Android使用Gridview单行横向滚动显示的具体代码,供大家参考,具体内容如下要想实现滚动显示,layout布局
- 本文实例为大家分享了C#实现简单的计算器功能的具体代码,供大家参考,具体内容如下环境:VS2010及以上版本1、建立个Window窗体应用2
- Java continue break 制作简单聊天室程序,屏蔽不文明语言,显示每句话聊天时间package com.swift;impor
- 本文实例讲述了C# Socket网络编程技巧。分享给大家供大家参考。具体分析如下:客户端要连接服务器:首先要知道服务器的IP地址。而服务器里
- Maven修改打包文件名称对Maven打出的jar包名称不满意:想通过修改配置给jar包改名,查询找到了方法:pom.xml的<bui
- 一、结论先行ArrayList在JDK1.8与JDK1.7底层区别JDK1.7:ArrayList像饿汉式,直接创建一个初始容量为10的数组
- Listview现在用的很少了,基本都是使用Recycleview,但是不得不说Listview具有划时代的意义,拓展性很强,我们可以自己添
- 前言作为一个开发者,日常会接触到很多优秀的软件,其实,或多或少会有这样的想法,我能不能开发一个自己软件,甚至办公软件都希望是Markdown
- renameTo方法public boolean renameTo(File dest),File类中的renameTo方法可以操作文件或目
- 最近项目上产品经理提了个需求,要求关闭语言国际化,不管手机系统设置那个国家的语言,都要显示汉语,好吧,既然有需求,那就做吧。但是项目中已经有
- 1.问题描述在一个目录及子目录下查找 TXT或Java文件,从中搜索所有“对象”字样的行。在D盘中的所有文件中搜索含有“对象”的行。2.解题
- spring boot是个好东西,可以不用容器直接在main方法中启动,而且无需配置文件,方便快速搭建环境。可是当我们要同时启动2个spri