深入浅出设计模式——单例模式
Posted 苏凌峰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入浅出设计模式——单例模式相关的知识,希望对你有一定的参考价值。
1.单例模式介绍
2.用代码演示单例模式
3.总结
1.单例模式介绍
定义:所谓单例模式,就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个实例,并且该类只提供一个获取其对象实例的方法(静态方法)。
描述:
有些时候,我们系统只需要一个全局的对象,这样有利于我们协调系统的整体行为,节约资源。
比如说:
1)在某个服务中,需要一个对象来读取配置文件,那么有一个这样的对象来读取配置文件也就足够了。
2)比如说我们现在要提供一个线程池,那么大部分情况下线程池这种比较重量级的对象,几个功能模块统一有一个也就够了,因为他会有一个常驻线程数,如果线程池多了会浪费资源,所以这种对象也适合单例的。
以上这两种情况只用了单例的对象,节约了资源,简化了管理。
2.用代码演示单例模式
基本的实现思路
可以看出,单例模式要求一个服务只有一个这样的对象(永远都是相同对象),而且只有一个获取该实例的方法。
根据这个要求,主要实现有以下两个步骤:
1)将构造方法私有化,这样其它的代码就无法调用到该类的构造方法,就无法使用new的方法来创建对象,只能通过该类提供的静态方法来得到该类的唯一实例。
2)在该类内提供一个静态方法,当我们调用这个方法的时候,就能返回单例对象的引用。
单例模式一共有8种写法,
1)饿汉式(静态常量)
2)饿汉式(静态代码块)
3)懒汉式(线程不安全)
4)懒汉式(线程安全,同步写法)
5)懒汉式(线程安全,同步代码块)
6)双重检查
7)静态内部类
8)枚举
我们来每一种写法都来介绍一遍:
1)饿汉式(静态常量 可用)
public class Singleton {
private static Object target = new Object();
private Singleton() {
}
public static Object getInstance(){
return target;
}
}
优点:写法比较简单,就是在类加载的时候就已经完成了实例化。
缺点:在类装载的时候就完成初始化,没有达到lazy Loading的效果。如果从始至终都未用过这个实例,则可能会造成内存浪费。
2)饿汉式(静态代码块 可用)
public class Singleton {
private static Object target = new Object();
private Singleton() {
}
public static Object getInstance(){
return target;
}
}
这种方式其实和第一种类似,优缺点也是一样的。
3)懒汉式(线程不安全 不可用)
public class Singleton3 {
private static Object target = null;
private Singleton3() {
}
public static Object getInstance(){
if(target==null){
target = new Object();
}
return target;
}
}
优点:起到了懒加载的效果,可以或多或少节约一点资源。
缺点:只能在单线程的模式下,才适用,多线程可能会创建多个单例对象,造成资源浪费。(线程A进入了if判断之后,时间片结束,另一个线程B也通过了这个语句,然后又调度线程A,继续又创建了一个对象,就产生了多个实例。)
4)懒汉式(线程安全,同步写法 不推荐使用)
public class Singleton4 {
private static Object target = null;
private Singleton4() {
}
public static synchronized Object getInstance(){
if(target==null){
target = new Object();
}
return target;
}
}
优点:有懒加载的效果,又线程安全。
缺点:效率太低了,不仅仅创建的时候,每个线程想获得实例的时候,都要进行同步,其实只要在要实例的时候进行同步就行了,如果对象已经存在的话直接返回就好了。
5)懒汉式(线程安全,同步代码块 不可用)
public class Singleton5 {
private static Object target = null;
private Singleton5() {
}
public static Object getInstance() {
if (target == null) {
synchronized (Singleton5.class) {
target = new Object();
}
}
return target;
}
}
优点:优化了第四种方案,可以让获取对象的速度变快
缺点:还是会有线程安全问题,(线程A进入了if判断之后,时间片结束,另一个线程B也通过了这个语句,然后又调度线程A,继续又创建了一个对象,就产生了多个实例。)
6)双重检查 推荐使用
public class Singleton6 {
private static Object target = null;
private Singleton6() {
}
public static Object getInstance() {
if (target == null) {
synchronized (Singleton6.class) {
if (target == null) {
target = new Object();
}
}
}
return target;
}
}
优点:进行了两次检查之后,就不怕多线程同时读取的情况了。
7)静态内部类 推荐使用
public class Singleton7 {
private static class SingletonInstance {
private static final Object target = new Object();
}
private Singleton7() {
}
public static Object getInstance() {
return SingletonInstance.target;
}
}
优点:类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。
8)枚举 推荐使用
public enum SingletonEnum {
INSTANCE;
public void doSomething() {
System.out.println("doSomething");
}
}
优点:保证了安全性和唯一性。
缺点:所以在实际项目开发中,很少见人这么写过
3.总结
单例模式应该是设计模式中最简单的一种模式了。它有以下几个要素:
1)私有的构造方法
2)指向自己实例的私有静态引用
3)以自己实例为返回值的静态的公有的方法
至于使用哪种方式获取,一般视情况而定。
以上是关于深入浅出设计模式——单例模式的主要内容,如果未能解决你的问题,请参考以下文章