单例模式
单例模式(Singleton) ,也叫单子模式,是一种常用的设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。选择单例模式就是为了避免不一致状态,避免政出多头。
三要素:
- 私有的构造方法;
- 指向自己实例的私有静态引用;
- 以自己实例为返回值的静态的公有方法。
优点:
- 在内存中只有一个对象,节省内存空间;
- 避免频繁的创建销毁对象,可以提高性能;
- 避免对共享资源的多重占用,简化访问;
- 为整个系统提供一个全局访问点。
饿汉模式:线程安全
``` // 饿汉式单例 public class Singleton1 {
// 指向自己实例的私有静态引用,主动创建
private static Singleton1 singleton1 = new Singleton1();
// 私有的构造方法
private Singleton1(){}
// 以自己实例为返回值的静态的公有方法,静态工厂方法
public static Singleton1 getSingleton1(){
return singleton1;
}
} ```
懒汉模式:非线程安全
``` // 懒汉式单例 public class Singleton2 {
// 指向自己实例的私有静态引用
private static Singleton2 singleton2;
// 私有的构造方法
private Singleton2(){}
// 以自己实例为返回值的静态的公有方法,静态工厂方法
public static Singleton2 getSingleton2(){
// 被动创建,在真正需要使用时才去创建
if (singleton2 == null) {
singleton2 = new Singleton2();
}
return singleton2;
}
} ```
加锁:
``` // 线程安全的懒汉式单例 public class Singleton2 {
private static Singleton2 singleton2;
private Singleton2(){}
// 使用 synchronized 修饰,临界资源的同步互斥访问
public static synchronized Singleton2 getSingleton2(){
if (singleton2 == null) {
singleton2 = new Singleton2();
}
return singleton2;
}
}
// 线程安全的懒汉式单例 public class Singleton2 {
private static Singleton2 singleton2;
private Singleton2(){}
public static Singleton2 getSingleton2(){
synchronized(Singleton2.class){ // 使用 synchronized 块,临界资源的同步互斥访问
if (singleton2 == null) {
singleton2 = new Singleton2();
}
}
return singleton2;
}
} //缺点 锁粒度粗 锁整个方法 ```
内部类加载
``` // 线程安全的懒汉式单例 public class Singleton5 {
// 私有内部类,按需加载,用时加载,也就是延迟加载
private static class Holder {
private static Singleton5 singleton5 = new Singleton5();
}
private Singleton5() {
}
public static Singleton5 getSingleton5() {
return Holder.singleton5;
}
} ```
doublecheck:
``` // 线程安全的懒汉式单例 public class Singleton3 {
//使用volatile关键字防止重排序,因为 new Instance()是一个非原子操作,可能创建一个不完整的实例
private static volatile Singleton3 singleton3;
private Singleton3() {
}
public static Singleton3 getSingleton3() {
// Double-Check idiom
if (singleton3 == null) {
synchronized (Singleton3.class) { // 1
// 只需在第一次创建实例时才同步
if (singleton3 == null) { // 2
singleton3 = new Singleton3(); // 3
}
}
}
return singleton3;
}
} ```
volatile:
指令重排序-内存屏障-原子性 (自行查验)
private:
控制访问入口
static:
全局唯一可用(回答这个就肤浅了)
不依赖类特定的实例,被类的所有实例共享
对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存