JAVA的单例模式(singleton)
- 一、什么是单例模式?
- 1. 优点
- 2. 缺点
- 3. 使用场景
- 二、什么是线程安全和非线程安全?
- 1.线程安全
- 2.非线程安全
- 3.线程安全与不安全的本质区别
- 三、单例模式的5种创建方式
- 1.饿汉式
- 2.懒汉式
- 3.双重锁检测模式(Double Check Lock)
- 4.静态内部类模式
- 5.通过枚举实现单例模式
一、什么是单例模式?
单例模式是一个类只有一个实例对象。其构造函数是私有的,不能通过new方式创建实例对象。在整个程序的生命周期内都只存在一个单例类的实例对象,以静态方法或枚举返回唯一的实例化对象。
1. 优点
①在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
② 避免对资源的多重占用(比如写文件操作)。
2. 缺点
没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
3. 使用场景
①要求生产唯一序列号。
② WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
③ 创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
注意事项:getInstance() 方法中需要使用同步锁 synchronized () 防止多线程同时进入造成 instance 被多次实例化
二、什么是线程安全和非线程安全?
1.线程安全
线程安全就是多线程访问时,采用了加锁机制,当一个线程访问某一个类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染的情况。
2.非线程安全
线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据,从而导致数据不一致,造成所得到的数据是脏数据
3.线程安全与不安全的本质区别
线程安全与不安全的本质区别在于对于共享资源的访问上的执行效果.安全线程在处理共享资源时效果具有原子性,即必须等到当前线程访问结束后别的线程才能继续访问.而非安全线程则任何时候都可以抢占cpu的使用权,导致的结果就是线程共享资源由于多线程争抢访问导致的数据错误问题.
三、单例模式的5种创建方式
1.饿汉式
//类加载时就创建一次实例,避免了多线程问题,但是还在使用就创建了对象,浪费内存
//线程安全
public class Singleton {
private Singleton() {}
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
2.懒汉式
//优点:需要的时候才进行创建
//缺点:线程不安全,多线程时会创建多个实例
public class Singleton {
private Singleton() {}
private static Singleton instance = null;
public static Singleton getInstance() {
if (null == instance) {
instance = new Singleton();
}
return instance;
}
}
//优点:线程安全,但是在多线程情况下还是有可能出现不安全的情况,
//threadA和threadB同时执行到if (null == instance)时就与可以出现创建多个实现
//缺点:添加了synchronized的函数比一般方法慢得多,若多次调用getInstance,则累积的性能损耗特别大。
public class Singleton {
private Singleton() {}
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
if (null == instance) {
instance = new Singleton();
}
return instance;
}
}
3.双重锁检测模式(Double Check Lock)
//多线程情况下还是可能出现创建多个实例情况,主要是因为jvm对命令进行重排序优化,而导致创建多个实例的情况。
public class Singleton {
private Singleton() {}
private static Singleton instance = null;
public static Singleton getInstance() {
if (null == instance) {
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
}
//优点:线程安全,volatile关键词主要是保证多线程之间的可见性,保证线程在每次取值volatile变量都是最新值
//volatile关键字主要是禁止命令重排序的,但是volatile不是原子性的
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (null == instance) {
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
}
4.静态内部类模式
public class Singleton {
private Singleton() {}
private static Singleton getInstance() {
return SingletonHolder.instance;
}
private static class SingletonHolder {
//静态变量值会初始化一次
private static Singleton instance = new Singleton();
}
}
5.通过枚举实现单例模式
//优点:既能避免多线程同步问题,又能防止反序列化重新创建新的对象
public enum Singleton {
INSTANCE;
public void doSimthing(){
}
}
参考文献:
Java单例模式的5种实现方法
单例模式
Java创建线程安全的单例singleton
volatile关键词
什么是指令重排序?为什么要重排序