- 饿汉式
1
2
3
4
5
6
7
8
9
10
11
12
13public class Mgr01 {
private static final Mgr01 INSTANCE = new Mgr01();
private Mgr01(){}
private static Mgr01 getInstance(){return INSTANCE;}
public void m(){
System.out.println("m");
}
public static void main(String[] args) {
Mgr01 m1 = Mgr01.getInstance();
Mgr01 m2 = Mgr01.getInstance();
System.out.println(m1 == m2);
}
}类加载到内存后就实例化一个单例 , JVM 保证线程安全
缺点: 不管是否用到,类装载时就完成实例化 (通常问题不大,写法简单) - 懒汉式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31public class Mgr02 {
private volatile static Mgr02 INSTANCE;
private Mgr02(){};
/**
* 可以使用线程锁的方式(synchronized 修饰此方法)解决,但是性能会下降
* @return
*/
public static Mgr02 getInstance(){
if (INSTANCE == null) {
// 或者在此处加锁,解决线程安全问题
synchronized (Mgr02.class){
if (INSTANCE == null ){
INSTANCE = new Mgr02();
}
}
}
return INSTANCE;
}
public void m(){
System.out.println("m");
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
// 同一个类的 不同对象,它的 hashCode 是不同的
System.out.println(Mgr02.getInstance().hashCode());
}).start();
}
}
}为了保证线程安全,写法相对饿汉式麻烦,但是只有在使用时才会实例化
- 静态内部类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class Mgr03 {
private Mgr03(){}
private static class Mgr03Holder {
private static final Mgr03 INSTANCE = new Mgr03();
}
public static Mgr03 getInstance() {
return Mgr03Holder.INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
// 同一个类的 不同对象,它的 hashCode 是不同的
System.out.println(Mgr03.getInstance().hashCode());
}).start();
}
}
}与饿汉式类似,都是由 JVM 保证线程安全,但静态内部类是延迟加载
- 枚举
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public enum Mgr04 {
//枚举单例
INSTANCE;
public void m(){
System.out.println("m");
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
// 同一个类的 不同对象,它的 hashCode 是不同的
System.out.println(Mgr04.INSTANCE.hashCode());
}).start();
}
}
}枚举单例,解决线程同步,解决反序列化(不能通过反射拿到多个实例,枚举没有构造方法)