介绍
核心作用
保证一个类只有一个实例,并且对外提供一个访问该实例的全局访问点。
优点
- windows 系统的任务管理器、回收站;
- 项目中读取配置文件的类,一般配置文件只需要读取一次,所以只需要一个读取配置文件的类;
- 网站的计数器
- 应用程序中日志应用,一般都是单例模式实现,由于共享的日志文件一直处于打开状态,只能有一个实例操作,否则不好追加
- 数据库的连接池设计
- 操作系统的文件系统
- 在 Spring 中,每个 bean 默认是单例,这样做的优点是 Spring 容器很好的管理
- 在 Servlet 编程中,每个 Servlet 也是单例
-
步骤
私有化构造方法
- 提供私有的静态的对象的实例属性
-
五种单例模式
饿汉式(线程安全,调用效率高,但是不能延时加载)
- 懒汉式(线程安全,调用效率不高,但是可以延时加载)
- 双重检测锁式(由于 JVM 底层内部模型原因,偶尔会出现问题,不建议使用)
- 静态内部类式(线程安全,调用效率高,可以延时加载)
- 枚举单例(线程安全,调用效率高,不能延时加载,实现简单。由于 JVM 从根本上提供保障,避免通过反射和反序列化的漏洞)
饿汉式
```java package singleton;
/**
- 饿汉式单例模式
- 类加载时,立即加载这个对象。加载类是,天然的线程安全 *
- @author SIMBA1949
@date 2019/6/5 21:20 */ public class Singleton01 {
private static Singleton01 instance = new Singleton01();
private Singleton01() { }
public static Singleton01 getInstance(){
return instance;
懒汉式
```java package singleton;
/**
- 懒汉式单例模式
- 延时加载,资源利用率高,并发情况下 synchronized 效率低
- @author SIMBA1949
@date 2019/6/5 21:39 */ public class Singleton02 { // volatile 保证 instance 在所有线程中同步 private static volatile Singleton02 instance;
private Singleton02() {
// 私有化构造方法避免类在外部被实例化
}
public static synchronized Singleton02 getInstance(){
if (null == instance){
instance = new Singleton02();
}
return instance;
双重检测锁式
```java package singleton;
/**
- 双重检测锁单例模式
- @author SIMBA1949
@date 2019/6/5 21:44 */ public class Singleton03 {
private static volatile Singleton03 instance;
private Singleton03() { }
public static Singleton03 getInstance(){
if (null == instance){
synchronized (Singleton03.class){
if (null == instance){
instance = new Singleton03();
}
}
}
return instance;
静态内部类式
```java package singleton;
/**
- 静态内部类单例模式
- 类初始化的时候不会将内部类一起初始化,只有调用的时候才会加载静态内部类,加载类时线程时安全的
- INSTANCE 是 static final 修饰的,保证内存中只有一个实例存在
- 兼备并发高效调用和延时加载的优势
- @author SIMBA1949
@date 2019/6/5 21:54 */ public class Singleton04 {
private Singleton04() { }
private static class Singleton04Inter{
public static final Singleton04 INSTANCE = new Singleton04();
}
public static Singleton04 getInstance(){
return Singleton04Inter.INSTANCE;
枚举单例
```java package singleton;
/**
- @author SIMBA1949
- @date 2019/6/5 22:01 / public enum Singleton05 { /*
/**
- 避免反射创建多个对象,在构造方法中判断如果实例属性不为 null 时,抛出异常即可 *
- @author SIMBA1949
@date 2019/6/5 22:08 */ public class Singleton064Reflect {
private static Singleton064Reflect instance = new Singleton064Reflect();
private Singleton064Reflect() {
if (null != instance){
throw new RuntimeException();
}
}
public static Singleton064Reflect getInstance(){
return instance;
避免反序列化创建多个对象
```java package singleton;
import java.io.*;
/**
- 添加 readResolve() 方法可以避免反序列化创建多个对象
- @author SIMBA1949
@date 2019/6/5 22:12 */ public class Singleton074Serializable implements Serializable{
private static final long serialVersionUID = -3093202203157151493L; private static Singleton074Serializable instance = new Singleton074Serializable();
private Singleton074Serializable() { }
public static Singleton074Serializable getInstance(){
return instance;
}
/**
- 添加 readResolve() 方法可以避免反序列化创建多个对象
- @return */ private Object readResolve(){ return instance; } }
class DeserializableTest{ public static void main(String[] args) throws IOException, ClassNotFoundException { Singleton074Serializable instance = Singleton074Serializable.getInstance(); // 序列化 FileOutputStream fis = new FileOutputStream(new File(“T:/s.java”)); ObjectOutputStream oos = new ObjectOutputStream(fis);
oos.writeObject(instance);
// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("T:/s.java")));
Singleton074Serializable deInstance = (Singleton074Serializable) ois.readObject();
System.out.println(instance == deInstance);
}
} ```