一般的单例模式
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
此方式已知问题:
1.如果由不同的ClassLoader去load,有可能存在多个实例。
2.线程不安全。假设线程1进入if判断,正在创建对象的时候,线程2进入,判断成功,这样就会创建2个对象实例。
改进方式,同步化getInstance方法,也就是懒汉式写法。
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
但getInstance会被外部线程比较频繁的调用,同步比非同步的性能消耗要昂贵很多,因此这样的做法会存在很大的额外性能消耗。因此产生另外一种改进方式,双重检查写法。
public static Singleton getInstance() {
if(singleton == null) {
synchronized(Singleton.class) {
if(singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
此写法存在的问题在于singleton = new Singleton() 这句代码对于编译器来说,是分两步进行。首先初始化一个singleton对象并随意赋一个值,然后调用Singleton类的构造器赋值。因此在第一步完成后singleton == null这句判断已经不成立了,但此时singleton只是一个临时值。如果线程2此时进入getInstance,就会把这个singleton给返回出去。由于java的内存模型,双重检查并不能成功的起到作用。
采用饿汉式的写法也可避免线程安全问题.但是任何对Singleton类的访问(内部的static final变量除外,因为jvm会把它们直接编译为常量),比如另外一个static方法被访问,会引起jvm去初始化instance,而此时我们的本意是不想加载单例类的。同时因为没有延迟加载,最明显的缺点就是如果构造器内的方法比较耗时,则加载过程会比较长。对于一般的应用,构造方法内的代码不涉及到读取配置、远程调用、初始化IOC容器等长时间执行的情况,用这种方式是最简单的。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
如果我们既想使用延迟加载的好处,让类在被使用的时候才去加载,又想避免额外的同步调用开销,同时还不使用双重检查的模式,可以用初始化一个中间的容器类来解决这个问题。
就可以用如下的写法:
public class Singleton {
private static class SingletonHolder {
static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
private Singleton() { }
}
java中,只有一个类被用到的时候才被初始化。在getInstance方法被调用的时候,如果SingletonHolder类没有被加载,就会去加载,起到延迟加载的作用,同时也能保持多线程下的语义正确性。
如果是jdk1.5以上,还可采用enum方式来实现,也可避免多线程的问题。
enum Singleton {
INSTANCE;
public static Singleton getInstance() {
return INSTANCE;
}
public void sss() {
System.out.println("sss");
}
}
关于反射
以上的写法,除了枚举方式,其他的写法均可用反射得到Constructor来newInstance得到实例。
关于继承
无论是饿汉式,懒汉式写法均不可继承,因此有如下登记式写法。
public class Sington {
private static HashMap<String, Sington> map = new HashMap<String, Sington>();
protected Sington() {
}
public static synchronized Sington getInstance(String classname) {
Sington singleton = (Sington) map.get(classname);
if (singleton != null) {
return singleton;
}
try {
singleton = (Sington) Class.forName(classname).newInstance();
} catch (ClassNotFoundException cnf) {
} catch (InstantiationException ie) {
} catch (IllegalAccessException ia) {
}
map.put(classname, singleton);
return singleton;
}
}
对于子类的
public class SingtonChild extends Sington {
public SingtonChild() {
}
static public SingtonChild getInstance() {
return (SingtonChild) Sington
.getInstance("util.SingtonChild");
}
public String about() {
return "Hello,I am children.";
}
}
ClassLoader对单例的影响
同样的单例类,由不同的ClassLoader装载就会有多个实例,为了确保我们的单例类只会被同个类ClassLoader加载,我们就需要为它指定一个ClassLoader
private static Class getClass(String classname)
throws ClassNotFoundException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if(classLoader == null)
classLoader = Singleton.class.getClassLoader();
return (classLoader.loadClass(classname));
}
}
序列化对单例的影响
如果单例类实现了序列化接口,我们序列化一次,然后反序列化多次,会得到多个不同实例。我们通过实现readResolve()来解决这个问题。
public class Singleton implements Serializable {
private static Singleton instance = null;
private Singleton() { }
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
private Object readResolve() {
return instance;
}
}
JavaAPI中有哪些用到了单例模式
Runtime类
Runtime.getRuntime();
它里面用到的是饿汉式写法。
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
Note:网上查到不少文章说Calendar类是singleton模式的应用,进入JDK1.5的sourcecode,发现并不是这样,纯粹是谬误。
很简单的代码就可以验证:
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
Runtime runtime1 = Runtime.getRuntime();
Runtime runtime2 = Runtime.getRuntime();
System.out.println(c1 == c2);
System.out.println(runtime1 == runtime2);
分享到:
相关推荐
singleton pattern 的定义 主要应用方法 优缺点 通过代码 具体分析解释
单例模式(Singleton Pattern)是一种常用的软件设计模式,在系统中确保某个类只有一个实例,并提供一个全局访问点。这种模式通常用于控制资源的消耗,比如数据库连接、线程池等,以及确保某个系统配置的一致性。 #...
单例模式(Singleton Pattern)是软件设计模式中的一种,它保证一个类只有一个实例,并提供一个全局访问点。这种模式在很多场景下非常有用,比如控制资源的唯一性、全局配置对象或者缓存服务等。本篇文章将深入探讨...
### 单例模式 Singleton Pattern #### 概述 单例模式是一种常见的设计模式,属于创建型模式之一。这种模式的核心在于确保某个类只有一个实例存在,并且提供一个全局访问点来获取该实例。单例模式在Java开发中尤其...
Java据说有23种设计模式,Android的设计模式肯定是由Java来引申出来的。这里不讨论有多少人全会,有多少种设计模式会使用到,我们来讲下其中用得最多的也就是人人都知道的...这里是一个简单的SingletonPatternDemo。
**单例模式(Singleton Pattern)**是软件设计模式中的一种基础模式,它的核心思想是确保一个类只有一个实例,并提供一个全局访问点。这种模式在很多场景下非常有用,比如配置管理、线程池、数据库连接池等,这些都...
单例模式是软件设计模式中的一种,属于创建型模式,它的主要目的是确保一个类只有一个实例,并提供一个全局访问点。这种模式在很多场景下都非常有用,例如管理共享资源、配置对象或者缓存服务等。 单例模式的核心...
在Java编程中,单例模式是一种常用的创建型设计模式,用于确保一个类只有一个实例,并提供一个全局访问点。本主题探讨的是线程安全的单例模式实现,特别是饥饿模式(Starvation)和延迟加载(Lazy Initialization)...
Java软件设计模式是一种在开发过程中遵循的成熟、可重用的解决方案模板,它解决了软件设计中的常见问题。设计模式并不具体实现任何代码,而是提供了一种通用的语言,帮助开发者理解和交流复杂的系统架构。以下是关于...
jar cvf singleton.jar ./ (当前目录打包,D:\\workspace\\java\\src\\com\\javaeye\\lindows\\design23) 博文链接:https://lindows.iteye.com/blog/221957
1. 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供全局访问点。单例模式的实现有多种方式,如饿汉式初始化、静态块初始化、懒汉式初始化、线程安全的单例、Bill Pugh实现方式和枚举实现方式。例如...
单例模式是软件设计中的...在Java中,我们可以使用多种方式来实现单例,包括传统的同步方法、双重检查锁定和枚举。然而,使用单例模式时,也需要考虑其可能带来的问题,如测试困难、违背开闭原则等,以便做出最佳选择。
在这个名为"JAVA design pattern-java设计模式"的CHM文件中,我们可能找到了关于如何在Java开发中应用设计模式的详细信息。 设计模式通常分为三大类:创建型、结构型和行为型。创建型模式关注对象的创建,如单例...
单例模式(Singleton Pattern)是一种常用的软件设计模式,它的核心思想是确保一个类在整个应用程序中只有一个实例存在,并提供一个全局访问点来获取这个实例。这种模式在很多场景下非常有用,比如管理系统资源、...
### 设计模式在Java中的应用 #### 设计模式概述与背景 设计模式是软件工程领域的一个重要概念,它提供了一套解决常见问题的有效方案。这些模式不仅能够帮助开发者编写更高质量、可维护性更强的代码,还能促进团队...
- 单例模式(Singleton Pattern):保证一个类只有一个实例,并提供一个全局访问点。在Java EE中,单例模式常用于管理状态信息或共享资源。 - 依赖注入(Dependency Injection)和CDI(Contexts and Dependency ...
- 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局访问点。书中讨论了单例模式的实现方式,如通过异常抛出、静态类和静态方法创建单例,以及在大型程序中查找单例的挑战和影响。 - 建造者...
单例模式是设计模式中的一种,它用于控制类的实例化过程,确保在整个应用程序中,对于特定类,只有一个实例存在。这种模式常被用来管理共享资源或者全局配置,以提高性能和减少系统间的耦合。 单例模式的核心在于...