什么是单例模式
一个类对象从始至终只需要一个实例,避免多次实例造成资源浪费(个人理解是防止每次都new 一个新对象)
实现方式:
一、饿汉式单例
在类加载到内存后,就直接实例化。由JVM保证只有一个实例(线程安全)
缺点:不管用不用这个类,它都会实例化(个人感觉用这个就够了吧。。。好像也不会占用多少空间的样子)
public class Singleton1 {
private static final Singleton1 INSTANCE = new Singleton1();
/**
* 将构造函数私有化,不让他人从外部实例化(除非通过反射)
**/
private Singleton1() {
}
public static Singleton1 getInstance() {
return INSTANCE;
}
public void doSomething() {
}
public static void main(String[] args) {
Singleton1 instance = Singleton1.getInstance();
instance.doSomething();
}
}
- 使用 static 修饰的INSTANCE静态变量 在类加载后就会初始化赋值,产生一个 Singleton1实例。
- final 修饰的变量不可被改变,一旦获得了初始值,该 final 变量的值就不能被重新赋值(保证的是它引用的地址不发生改变,但这个对象可以发生变化)。
二、懒汉式单例
在调用自定义实例化方法时再进行实例化;但为了避免多线程下重复创建问题,需要特殊处理
public class Singleton2 {
private static volatile Singleton2 INSTANCE;
private Singleton2() {
}
public static Singleton2 getInstance() {
if (INSTANCE == null) {
// 防止多线程下重复实例化问题
synchronized (Singleton2.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton2();
}
}
}
return INSTANCE;
}
public void doSomething() {
}
public static void main(String[] args) {
Singleton2 instance = Singleton2.getInstance();
instance.doSomething();
}
}
- 当前 synchronized 锁的是 class ,是类锁
在 Java 中,针对每个类也有一个锁,可以称为“类锁”,类锁实际上是通过对象锁实现的,即类的 Class 对象锁。每个类只有一个 Class 对象,所以每个类只有一个类锁
- INSTANCE 实例对象使用 volatile 修饰 禁止指令重排序
对象实例化过程:
- 分配内存空间
- 初始化对象
- 将对象的引用指向分配的内存 如果发生指令重排序:
- 分配内存空间
- 将对象的引用指向分配的内存
- 初始化对象
- 第一次if判断的目的,是为了节约实例化时间,如果改对象已经实例就直接返回不需要再去获取锁
三、枚举单例
不论是懒汉还是饿汉式都可以通过反射的方式获取实例化对象,但枚举不需要实例化,也不会被反序列化
public enum SingletonEnum {
INSTANCE;
public void doSomething() {
System.out.println("do something");
}
public static void main(String[] args) {
// 直接调用方法,不需要实例化
SingletonEnum.INSTANCE.doSomething();
}
}
(但是,感觉写项目的时候好像没人会这么写吧。。。)
写在最后
第一次写文,如果有说的不准确的地方,大家一起互相交流~ 想着把23个设计模式都整理一遍(其实也是看到掘金2月发文累计还有奖品,有点心动啊!那个杯子感觉不错的样子~哈哈哈哈)
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
话说掘金网页版的编辑器换行也忒麻烦了吧,每次都要用‘左对齐’来换行的吗。。?
好吧。。原来是我low了