1、定义
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例
2、使用场景
确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一个。
3、五种常见的单例模式
1)饿汉单例模式(推荐)
package com.baofeng.singleton;
/**
* 饿汉单例模式
*
* @author sus
*
* 优点:加载类的时候就创建实例,所以线程安全
* 缺点:不能延迟加载
* 典型的空间换时间
*
*/
public class Singleton {
private static final Singleton singleton = new Singleton();
// 构造函数私有化
private Singleton() {
}
public void doSomething(){
System.out.println("do something");
}
public static Singleton getInstance() {
return singleton;
}
//call
//Singleton.getInstance().doSomething();
}
2)懒汉单例模式
/**
* 懒汉单例模式
*
* @author sus
*
* 优点:延迟加载
* 缺点:需要加锁才能实现多线程同步,但是效率会降低
* 典型的时间换空间
*/
public class Singleton1 {
private static Singleton1 singleton = null;
// 构造函数私有化
private Singleton1() {
}
public void doSomething(){
System.out.println("do something");
}
public static synchronized Singleton1 getInstance() {
if(singleton == null){
singleton = new Singleton1();
}
return singleton;
}
//call
//Singleton1.getInstance().doSomething();
}
3)双重检查锁定(Doublle Check Lock)单例模式(不太推荐)
/**
* 双重检查锁定(Doublle Check Lock)单例模式
*
* @author sus
*
* 麻烦,在当前Java内存模型中不一定都管用,(DCL失效问题)某些平台和编译器甚至是错误的,
* 因为singleton = new Singleton2()这种代码在不同编译器上的行为和实现方式不可预知。
*
*/
public class Singleton2 {
//JDK是1.5或之后的版本添加volatile关键字
//双重加锁机制的实现会使用一个关键字volatile,
//它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,
//所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。
private volatile static Singleton2 singleton = null;
// 构造函数私有化
private Singleton2() {
}
public void doSomething(){
System.out.println("do something");
}
public static Singleton2 getInstance() {
//第一层判空是为了避免不必要的同步
if (singleton == null) {
synchronized (Singleton2.class) {
//第二层判空是为了在null的情况下创建实例
if (singleton == null) {
singleton = new Singleton2();
}
}
}
return singleton;
}
//call
//Singleton2.getInstance().doSomething();
}
4)静态内部类单例模式(推荐)
/**
* 静态内部类单例模式
*
* @author sushuai
*
*延迟加载,减少内存开销。因为用到的时候才加载,避免了静态field
*在单例类加载时即进入到堆内存的permanent代而永远得不到回收的缺点(大多数垃圾回收算法是这样)。
*
*类级的内部类,也就是静态类的成员式内部类,该内部类的实例与外部类的实例
* 没有绑定关系,而且只有被调用时才会装载,从而实现了延迟加载
*/
public class Singleton3 {
// 构造函数私有化
private Singleton3() {
}
public static Singleton3 getInstance() {
return SingletonHolder.singleton;
}
public void doSomething(){
System.out.println("do something");
}
private static class SingletonHolder {
/**
* 静态初始化器,由JVM来保证线程安全
*/
private static final Singleton3 singleton = new Singleton3();
}
//call
//Singleton3.getInstance().doSomething();
}
5)包含单个元素的枚举类型的单例模式(极力推荐)
/**
* 包含单个元素的枚举类型的单例模式
*
* @author sus
*
* 很好,不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
* 但是失去了类的一些特性,没有延迟加载,用的人也太少了~~
*/
public enum Singleton4 {
INSTANCE; //定义一个枚举的元素,就代表Singleton4的一个实例
public void doSomething(){
System.out.println("do something");
}
//call
//Singleton4.INSTANCE.doSomething();
//单元素的枚举类型已经成为实现Singleton的最佳方法
}