五种实现方式
1.饿汉式
1 | public class Singleton{ |
类加载的时候就会创建对象,只会创建一次,在多线程情况下仍然能保持唯一的实例。如果单例类占用比较大的内存,创建饿汉式就不是一个太好的选择
2.懒汉式
1 | public class Singleton{ |
需要的时候才实例化对象,实现了延缓加载,但是,在多线程中无法保证示例的唯一性。
加锁的懒汉式1
2
3
4
5
6
7
8
9
10
11
12
13
14public class Singleton{
private static Singleton instance;
private Singleton() {};
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
3. DCL(Double Check Lock , 双重校验锁)
1 | public class Singleton{ |
4.静态内部类
1 | public class Singleton{ |
利用JVM类加载机制,线程安全
5.枚举
1 | public enum Singleton{ |
所有枚举常量都通过静态代码块来进行初始化,即在类加载期间就初始化,这样保证了每个枚举类型及枚举常量都是不可变的,所以枚举类型的单例是线程安全的。
synchronized
synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized 方法和 synchronized 块。
Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线程访问object的一个加锁代码块时,另一个线程仍可以访问该object中的非加锁代码块。
volatile
当一个变量被volatile
修饰后,将具备两种特性:
可见性:保证此变量对所用线程的可见性
禁止指令重排序优化
单例模式的序列化和反序列化
对单例类的实例的序列化会破会单例模式的唯一性,反序列化会得到一个不同的实例。
解决办法:在单例类中定会readResolve
方法,以DCL为例1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public class Singleton{
private static volatile Singleton instance;
private Singleton() {};
public static Singleton getInstance(){
if(instance == null){ // 如果已经创建,就不会获取对象锁,提高性能
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
private Object readResolve(){
return instance;
}
}
单例模式与反射
Java的反射机制可以破坏单例模式1
2
3
4
5
6
7
8
Class<Singleton> classType = Singleton.class;
Constructor<Singleton> constructor = classType.getDeclaredConstructor(null);
constructor.setAccessible(true);
Singleton singleton1 = constrctor.newInstance();
Singleton singleton2 = Singleton.getInstance();
singleton1.equals(singleton2) // 结果是false
解决措施,以DCL为例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
26public class Singleton{
private static volatile Singleton instance;
private static boolean flag = false;
private Singleton() {
synchronized(Singleton.class){
if(!flag){
flag = true;
}else{
throw new RuntimeException("单例对象被重复创建");
}
}
}
public static Singleton getInstance(){
if(instance == null){ // 如果已经创建,就不会获取对象锁,提高性能
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
常见单例模式应用
1.EventBus.getDefault()
1 |
|
2. Picasso.get()
1 | /** |
3. InputMethodManager.getInstance()
1 | public final class InputMethodManager { |