单例模式的编写有多种方式,但是有些细节的地方容易被大家忽略,在这里我简单的向大家分享一下,如有不正确的地方,还望指正。
经典的单例模式有两种方式一种是饿汉式,一种是懒汉式。
先来提一下饿汉式,这个是最简单但是最不实用的。
public class SingleTone {
private SingleTone(){
}
private static SingleTone single = null;
//饿汉式
public static SingleTone getInstance(){
single = new SingleTone();
return single;
}
}
下面是比较简单的懒汉式编写,主要是为了保证创建的对象只有一个。
public class SingleTone {
private SingleTone(){
}
private static SingleTone single = null;
//懒汉式
public static SingleTone getInstance(){
if(single==null){
single = new SingleTone();
}
return single;
}
}
这种懒汉式存在线程安全问题,所以需要加同步锁,加同步锁,则有两种方式,一种是将synchronized加在方法上,另一种是将synchronized加在方法内。
public class SingleTone {
private SingleTone(){
}
private static SingleTone single = null;
public synchronized static SingleTone getInstance(){
if(single==null){
single = new SingleTone();
}
return single;
}
}
但是,synchronized加在方法会使效率低,因为锁的范围比较大,我们要向保证是单例的,其实主要是为了保证single = new SingleTone();是线程安全的就行,所以在加锁的时候,我们一般会将锁加到方法里面。
public class SingleTone {
private SingleTone(){
}
private static SingleTone single = null;
public static SingleTone getInstance(){
if(single==null){
synchronized (SingleTone.class) {
single = new SingleTone();
}
}
return single;
}
}
将锁加到里面后又会有新的问题,如果两个线程同时进入了getInstence()中后,并都判断了single等于null,其中一个进入同步锁中,另外一个在门口等待,当一个创建完对象后让出锁,另一个直接进去,这样它就会又创建对象,所以更好的方式是加双重锁定,这种方式是效率高,并且安全。
public class SingleTone {
private SingleTone(){
}
private static SingleTone single = null;
public static SingleTone getInstance(){
if(single==null){
synchronized (SingleTone.class) {
if(single==null){
single = new SingleTone();
}
}
}
return single;
}
}