一、单例模式具有以下特点:
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例
单例设计模式所解决的问题就是:保证类的对象在内存中唯一。
二、单例7种的写法
懒加载:用到对象时再创建
- 优点
提供了对唯一实例的受控访问。
由于在系统内存中只存在一个对象,因此可以节约系统资源,
对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
可以根据实际情况需要,在单例模式的基础上扩展做出双例模式,多例模式。 - 缺点
单例类的职责过重,里面的代码可能会过于复杂,在一定程度上违背了“单一职责原则”。
如果实例化的对象长时间不被利用,会被系统认为是垃圾而被回收,这将导致对象状态的丢失。
1. 饿汉模式
/**
* 单例实现-饿汉式
* 特点:线程安全,无法实现实例懒加载策略。
* 如何体现线程安全? static,一个类在JVM里只加载一次。延伸到类加载过程。getInstance方法处于使用阶段,此时已经加载完成,所以线程安全。
*/
public class Single1 {
private static final Single1 s=new Single1();
private Single1(){}
public static Single1 getInstance(){
return s;
}
}
2. 懒汉模式
/**
* 单例模式-懒汉式
*
* 懒汉式和饿汉式相比的区别就是懒汉式创建了延迟对象同时饿汉式的实例对象是被修饰为final类型。
*
* 优点:懒汉式的好处是显而易见的,它尽最大可能节省了内存空间。
* 缺点:在多线程编程中,使用懒汉式可能会造成类的对象在内存中不唯一,
* 虽然通过修改代码可以改正这些问题,但是效率却又降低了。
*
* 特点:线程不安全,实现了实例懒加载策略。
* 并发情况(线程不安全):当两个线程同时进入if语句的时候,第一个线程已经创建了一个对象,此时第 二个线程已经进入if语句,此时可能会创建两个对象。
*/
public class Single2 {
private static Single2 s = null;
private Single2() { }
public static Single2 getInstance() {
if (s == null)
s = new Single2();
return s;
}
}
3. 全局锁模式
/**
* 单例模式-全局锁式
*
* 特点:线程安全,且实现了懒加载策略,但是线程同步时效率不高。
synchronized对静态方法加锁,等于对当前类加锁。多线程并发时,只有一个线程能拿到锁进入if语句创建对象
*/
public class Single3 {
private static Single3 single3;
private Single3() {}
public synchronized static Single3 getInstance() {
if (single3 == null)
single3 = new Single3();
return single3;
}
}
4. 静态代码块模式
/**
* 静态代码块式
*
* 特点:线程安全,类主动加载时才初始化实例,实现了懒加载策略,且线程安全。
*
*/
public class Single4 {
private final static Single4 singleton4;
private Single4() { }
static {
singleton4 = new Single4();
}
public static Single4 getInstance() {
return singleton4;
}
}
5. 双重校验锁模式
/**
* 单例模式-双重校验锁式
* 特点:线程安全,且实现了懒加载策略,同时保证了线程同步时的效率。
* 但是volatile强制当前线程每次读操作进行时,保证所有其他的线程的写操作已完成。
* volatile使得JVM内部的编译器舍弃了编译时优化,对于性能有一定的影响。
* 当两个线程同时进入第一个if语句时,synchronized保证只能有一个线程拿到 * 锁,进入第二个if语句,所以线程安全。
*/
public class Single5 {
private static volatile Single5 singleton5;
private Single5() {}
public static Single5 getInstance() {
if (singleton5 == null) {
synchronized (Single5.class) {
if (singleton5 == null) {
singleton5 = new Single5();
}
}
}
return singleton5;
}
}
6. 静态内部类模式
/**
* 单例模式-静态内部类式【推荐】
* 特点:线程安全,不存在线程同步问题,
* 且单例对象在程序第一次 getInstance() 时主动加载 SingletonHolder 和其 静态成员 INSTANCE,
* 因而实现了懒加载策略。
1.没有用synchronized锁
2.不存在线程同步问题
3.jvm保证线程安全
*/
public class Single6 {
private Single6() {}
private static class SingletonHolder {
private static final Single6 INSTANCE = new Single6();
}
public static Single6 getInstance() {
return Single6.SingletonHolder.INSTANCE;
}
}
7. 枚举方式
/**
* 单例模式-枚举方式
*
* 特点:线程安全,不存在线程同步问题,且单例对象在枚举类型 INSTANCE
* 第一次引用时通过枚举的 构造函数 初始化,因而实现了懒加载策略。
*
* 这种方式是Effective Java作者 Josh Bloch 提倡的方式,
* 它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,
* 可谓是很坚强的壁垒啊。不过,由于JDK 1.5中才加入enum特性
*/
public class Single7 {
private Single7() {}
enum SingletonEnum {
INSTANCE;
private final Single7 singleton7;
private SingletonEnum() {
singleton7 = new Single7();
}
}
public static Single7 getInstance() {
return SingletonEnum.INSTANCE.singleton7;
}
}