一、为什么要使用单例设计模式?
当多个线程要操作同一对象,要保证对象的唯一性,以解决实例化过程中只实例化一次。
二、解决思路
1、有一个实例化的过程(只有一次),产生实例化对象。
2、提供返回实例对象的方法
二、单例模式的分类
1、饿汉式(可以深入了解JVM ClassLoader的加载机制)
示例代码如下:
/*
饿汉模式
1.线程安全性:在加载的时候已经被实例化(只有这一次),所以是线程安全的。
2.性能:没有延迟加载,若长时间不使用,实例对象会占用资源,影响性能。
*/
public class HungerySingleton {
// 在加载的时候就产生实例对象(由ClassLoader加载)
private static HungerySingleton instance = new HungerySingleton();
// 实例的属性会占用资源空间
private byte[] data = new byte[1024];
private HungerySingleton {
}
// 返回实例对象
public static HungerySingleton getInstance() {
return instance;
}
// 测试20个线程会返回同一个实例对象
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
new Thread(()->{
System.out.println(HungerySingleton.getInstance());
}).start();
}
}
}
2、懒汉式
示例代码如下:
/*
懒汉模式
1.线程安全性:多线程并发情况下不能保证实例对象的唯一性。
2.性能:实现了懒加载,性能相对饿汉式比较好。
*/
public class HoonSingleton {
private static HoonSingleton instance = null;
private HoonSingleton() {
}
// 在调用的过程中实例化对象并返回
public static HoonSingleton getInstance() {
if (null == instance) {
instance = new HoonSingleton();
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
new Thread(()->{
System.out.println(HoonSingleton.getInstance());
}).start();
}
}
}
3、懒汉式+同步方法
示例代码如下:
/*
懒汉模式 + 同步方法
1.线程安全性:通过增加synchronized保证了线程安全性。
2.性能:使用synchronized使得程序退化到了串行执行,降低了性能。
*/
public class HoonSingleton {
private static HoonSingleton instance = null;
private HoonSingleton() {
}
// 在调用的过程中实例化对象并返回(通过synchronized关键字修饰,保证线程安全性)
public synchronized static HoonSingleton getInstance() {
if (null == instance) {
instance = new HoonSingleton();
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
new Thread(()->{
System.out.println(HoonSingleton.getInstance());
}).start();
}
}
}
4、DCL(Double-Check-Locking):
/*
懒汉模式 + DCL
1.线程安全性:通过synchronized以及DCL保证了线程安全性。
2.性能:使用懒加载以及DCL,性能比较好。
3.CPU在执行过程中有可能导致实例对象中的实例属性(对象)指令重排,引起空指针异常。
/
public class HoonSingleton {
private static HoonSingleton instance = null;
private HoonSingleton() {
}
// DCL(Double-check-locking)
public static HoonSingleton getInstance() {
// 通过synchronized以及两次判断(DCL)保证线程安全性
if (null == instance) {
synchronized (HoonSingleton.class) {
if (null == instance) {
instance = new HoonSingleton();
}
}
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
new Thread(()->{
System.out.println(HoonSingleton.getInstance());
}).start();
}
}
}
通过volatile避免CPU指令重排导致空指针异常,进一步改良后的代码如下:
/*
懒汉模式 + DCL
1.线程安全性:通过synchronized以及DCL保证了线程安全性。
2.性能:使用懒加载以及DCL,性能比较好。
*/
public class HoonSingleton {
// 通过volatile避免CPU指令重排导致控制针异常
private volatile static HoonSingleton instance = null;
private HoonSingleton() {
}
// DCL(Double-check-locking)
public static HoonSingleton getInstance() {
// 通过synchronized以及两次判断(DCL)保证线程安全性
if (null == instance) {
synchronized (HoonSingleton.class) {
if (null == instance) {
instance = new HoonSingleton();
}
}
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
new Thread(()->{
System.out.println(HoonSingleton.getInstance());
}).start();
}
}
}
5、Holder
/*
持有者模式(Holder)
1.通过静态内部类实现懒加载,保证线程安全性,是目前应用比较广泛的一种单例模式
/
public class HolderDemo {
private HolderDemo() {
}
private static class Holder {
private static HolderDemo instance = new HolderDemo();
}
// 懒加载
// synchronized
//
public static HolderDemo getInstance() {
return Holder.instance;
}
}
6、枚举式
public enum EnumDemo {
// 常量,在加载的时候被实例化,且只能实例化一次
A, B, C, D;
public static void m1() {
System.out.println(“method”);
}
public static void main(String[] args) {
A.m1();
B.m1();
C.m1();
D.m1();
System.out.println(A.getClass().getName());// 输出结果:EnumDemo
System.out.println(B.getClass().getName());// 输出结果:EnumDemo
System.out.println(C.getClass().getName());// 输出结果:EnumDemo
System.out.println(D.getClass().getName());// 输出结果:EnumDemo
}
}
改良代码:
public enum EnumSingleton {
INSTANCE;
public static EnumSingleton getInstance() {
return INSTANCE;
}
}
改良
/*
同Holder(持有者模式)一样,是目前运用比较广泛的单例模式,大师结晶
*/
public enum EnumSingletonDemo {
private EnumSingletonDemo() {
}
private enum EnumHolder {
INSTANCE;
private EnumSingletonDemo instance;
EnumHolder() {
this.instance = new EnumSingletonDemo();
}
private EnumSingletonDemo getInstance() {
return instance;
}
}
public static EnumSingletonDemo getInstance() {
return EnumHolder.INSTANCE.instance;
}
}