设计模式 -(1)单例模式(singleton pattern)
单例模式可以简单理解为让某个类的某个对象称为系统中的唯一对象
饿汉式
饿汉式的意思是不管程序是否会用到这个类的对象都会初始化一个此类的对象,如下例,这种模式将类对象作为类的静态成员变量,而类的静态成员变量在类加载的时候就初始化完成了(具体可见:.class 加载过程),这样便可以保证程序在获取类实例时返回的都是同一个实例
/**
* 饿汉式
* 类加载到内存后,就实例化一个单例,JVM保证线程安全
* 推荐使用
* 唯一缺点,不管是否用到与否,类装载时就完成了实例化
*/
public class Singleton1 {
private static final Singleton1 singleton1 = new Singleton1();
private Singleton1() {
System.out.println("Singleton1 Constructor...");
}
public static Singleton1 getInstance() {
return singleton1;
}
public static void m(){
System.out.println("m ...");
}
public static void main(String[] args) {
Singleton1 s1 = Singleton1.getInstance();
Singleton1 s2 = Singleton1.getInstance();
System.out.println(s1 == s2);
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
}
}
运行结果:
Singleton1 Constructor...
true
1020371697
1020371697
懒汉式
以下方式的单例,只会在程序需要使用对象时才会实例化对象,所以称之为懒汉式,在 getInstance 方法中使用了双重检查上锁的方式,所以也称为 Double Check Lock (双重检查锁定)
package com.example.dp._01singleton;
/**
* 懒汉式
* 相比直接在 getInstance 方法上加 synchronized 关键字提高了效率,也保证了线程安全,如下例子中进行了双重检查
*/
public class Singleton3 {
private static Singleton3 singleton3 = null;
private Singleton3() {
System.out.println("singleton3 Constructor...");
}
public static Singleton3 getInstance() {
// 当 Singleton3 已经实例化时,第一层判空可以使程序直接返回结果,避免无效操作,调高效率
if (singleton3 == null) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (Singleton3.class) {
// 因为一层判空没有加锁,所以有可能有这种情况:A,B 线程都进入方法体,它们都判断 singleton3 为空
// 当线程 A 进入 synchronized 代码块时实例化 Singleton3,然后释放锁
// 然后线程 B 进入 synchronized 代码块,继续实例化 Singleton3 ,此时就违背了单例的理论,
// 所以此时要进行二次判空操作
if (singleton3 == null) {
singleton3 = new Singleton3();
}
}
}
return singleton3;
}
public static void m() {
System.out.println("m ...");
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
Singleton3 singleton3 = Singleton3.getInstance();
System.out.println(singleton3.hashCode());
}
}).start();
}
}
}
singleton3 Constructor...
1084725754
1084725754
1084725754
内部类方式
package com.example.dp._01singleton;
/**
* 静态内部类方式
* JVM保证单例
* 加载外部类时不会加载内部类,可以实现懒加载
*/
public class Singleton4 {
private Singleton4() {
System.out.println("singleton4 Constructor...");
}
private static class InnerClass {
private final static Singleton4 singleton4 = new Singleton4();
}
public static Singleton4 getInstance() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
return InnerClass.singleton4;
}
public static void m() {
System.out.println("m ...");
}
public static void main(String[] args) {
//调用m并不会初始化内部类
Singleton4.m();
Singleton4.getInstance();
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
Singleton4 singleton4 = Singleton4.getInstance();
System.out.println(singleton4.hashCode());
}
}).start();
}
}
}
枚举方式
/**
* 枚举方式
*/
public enum Singleton5 {
INSTANCE;
public static Singleton5 getInstance() {
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
Singleton5 singleton5 = Singleton5.INSTANCE;
System.out.println(singleton5.hashCode());
}
}).start();
}
}
}