一.什么是单例模式,为什么要用单例模式
- 什么是单例模式
一个类在整个系统中只有一个实例,而且这个实例是在类的内部通过一个private的构造方法构造的,外部不能调用其构造方法,只能获取它的实例。 - 为什么用
一则,解决多线程并发访问的问题。二则节约系统内存,提交系统运行的效率,提高系统性能。
二.单例模式的应用
1.外部资源:每台计算机有若干个打印机,但只能有一个PrinterSpooler,以避免两个打印作业同时输出到打印机。内部资源:大多数软件都有一个(或多个)属性文件存放系统配置,这样的系统应该有一个对象管理这些属性文件
2. Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~
3. windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
三.实现单例模式
- 懒汉式
1.线程不安全的懒汉式模式
package com.wangcc.DesignPartterns.singleton;
/**
* @ClassName: Singleton
* @Description: TODO(懒汉模式,lazy loading,线程不安全)
* @author cong
* @date 2017年9月24日 上午1:00:17
*
*/
public class Singleton {
private static Singleton singleton = null;
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
private Singleton() {
}
}
2.synchronized同步的懒汉式单例模式
package com.wangcc.DesignPartterns.singleton;
/**
* @ClassName: Singleton1
* @Description: TODO(这里用一句话描述这个类的作用)
* @author cong
* @date 2017年9月24日 上午1:30:14
*
*/
public class Singleton1 {
private static Singleton1 singleton1;
// 在方法上加锁保证线程安全,但是这个损耗性能
public static synchronized Singleton1 getInstance() {
if (singleton1 == null) {
singleton1 = new Singleton1();
}
return singleton1;
}
private Singleton1() {
}
}
3.双重检验锁
package com.wangcc.DesignPartterns.singleton;
/**
* @ClassName: Singleton2
* @Description: TODO(双重检测,这里有急需要解决的问题)
* @author cong
* @date 2017年9月24日 上午1:28:43
* http://blog.csdn.net/zhanlanmg/article/details/49944991
*/
public class Singleton2 {
// 注意加了volatile关键字
private static volatile Singleton2 singleton2;
/**
* @Title: getInstance @Description: TODO(这里用一句话描述这个方法的作用) @param @return
* 设定文件 @return Singleton2 返回类型 @throws
*
* 因为只有当singleton2==null时,才会new一个SingleTon2,要不然就是直接取原有的singleton2,这个时候只取值,
* 是不会造成数据异常的,是线程安全的,所以只需要针对singleton2==null的时候进行同步操作,我们要弄清楚真正的临界区
*/
public static Singleton2 getInstance() {
if (singleton2 == null) {
synchronized (Singleton2.class) {
if (singleton2 == null) {
singleton2 = new Singleton2();
}
}
}
return singleton2;
}
private Singleton2() {
}
}
- 饿汉式
package com.wangcc.DesignPartterns.singleton;
/**
* @ClassName: Singleton4
* @Description: TODO(饿汉式,线程安全,很稳)
* @author cong
* @date 2017年9月24日 上午1:27:46
*
*/
public class Singleton4 {
private static Singleton4 singleton4 = new Singleton4();
public static Singleton4 getInstance() {
return singleton4;
}
}
- 静态内部类
package com.wangcc.DesignPartterns.singleton;
/**
* @ClassName: Singleton3
* @Description: TODO(线程安全,静态内部类,我很喜欢)
* @author cong
* @date 2017年9月24日 上午1:28:12
*
*/
public class Singleton3 {
private Singleton3() {
}
private static class SingleHolder {
public static Singleton3 holder = new Singleton3();
}
public static final Singleton3 getInstance() {
return SingleHolder.holder;
}
}
枚举单例
package com.wangcc.DesignPartterns.singleton;
/**
* @ClassName: SingletonEnum
* @Description: TODO(枚举单例)
* @author cong
* @date 2017年9月24日 下午3:59:47
*
*/
public enum SingletonEnum {
INSTANCE;
// enum的构造方法只能是private权限
private SingletonEnum() {
// TODO Auto-generated constructor stub
// 做一些初始化的功能
}
}
大师Joshua Bloch 在其《Effective Java》中曾说,枚举单例是最好的单例模式实现方式。
它有以下优点。
- 代码简单
这个显而易见,就几行代码。
- 线程安全
了解enum枚举具体实现的很容易就知道,其实枚举的实现,其实就是一种天然的单例模式,而且很像前面所说的饿汉式单例,所以没有做到lazy-loading,但是很好的保证了线程安全。(这里插一句,为什么饿汉式就一定会保证线程安全呢,这是因为,singleton实例会在该类第一次初始化时初始化,在这个初始化过程中,作为类变量的singleton其实在之前的准备阶段中就已经执行了一次默认初始化(非primitive类型为null),当执行到初始化阶段时,初始化阶段是执行类构造器<()方法的过程。()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句中可以赋值,但是不能访问。虚拟机会保证一个类的()方法在多线程环境中被正确地加锁和同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的方法,其他线程都需要阻塞等待,直到活动线程执行()方法完毕。如果在一个类的()方法中有耗时很长的操作,那就可能造成多个线程阻塞,在实际应用中这种阻塞往往是很隐,所以,我们不用担心线程同步的问题(<>里看不见的为clinit) )
- 自由序列化
对于序列化和反序列化,因为每一个枚举类型和枚举变量在JVM中都是唯一的,即Java在序列化和反序列化枚举时做了特殊的规定,枚举的writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法是被编译器禁用的,因此也不存在实现序列化接口后调用readObject会破坏单例的问题。
http://www.cnblogs.com/ttylinux/p/6498822.html?utm_source=itdadao&utm_medium=referral
172万+

被折叠的 条评论
为什么被折叠?



