单例模式大家应该已经很熟悉了,但是在使用单例模式的时候,我们经常会忽略一个问题,那就是多线程情况下的单例模式的使用。一般单例模式的实现会有下面两种,分别是懒汉式和饿汉式。
##懒汉式实现1
2
3
4
5
6
7
8
9
10
11
12
13
14//懒汉式实现
public class Singleton{
private static Singleton instance = null;
private Singleton(){}
public static newInstance(){
if(null == instance){
instance = new Singleton();
}
return instance;
}
public void doSomething(){
// Do something ...
}
}
##饿汉式1
2
3
4
5
6
7
8
9
10
11//饿汉式
public class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton newInstance(){
return instance;
}
public void doSomething(){
// Do something ...
}
}
懒汉式和饿汉式的最大区别就是加载单例的时机的不同,也就是说空间和时间的问题。懒汉式是用空间换时间的典型,相反的饿汉式就是使用时间换空间的典型,上面的例子只是举了一个很简单的情况,假如这个单例对象很大非常占用内存,那么选择上述两种方式就会有很大的不同,要根据情况而确定到底使用哪一种。
但是不论选择上面的哪一种都会有一个问题那就是在多线程的情况下,如果是首次加载单例,就会出现生成多个单例的情况,这样如果是生成一个很大的单例对象的时候,加入这个单例对象的构造过程很复杂很耗时,那么在多线程情况下就会很容易出错,而且很耗内存,那么如何使用线程安全的单例模式呢?我们可以使用JVM自身来加载我们的单例模式,这样JVM自身在Load类的时候是线程安全的,因此我们可以利用这点写出线程安全的类。
##线程安全的类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class Singleton{
//内部类,在装载该内部类时才会去创建单利对象
private static class SingletonHolder{
public static Singleton instance = new Singleton();
}
private Singleton(){}
public static Singleton newInstance(){
return SingletonHolder.instance;
}
public void doSomething(){
//do something
}
}
利用JVM自身的特性之后,我们就再也不用担心多线程下单例模式的加载问题了。