单例模式的写法有很多种,但是看了横多人写的,都没有详细说明,对于初学者来说这还是有压力的。
下面几种单例模式是结合了我自己的理解。
第一种:创建静态的内部类变量。保证在类被加载的时候可以实例化该类的对象。通过提供一个公共的静态方法让外部可以通过该方法获得该对象的实例。
public class Singleton1{
private static Singleton1 sing=new Singleton1();
private Singleton1(){}
private static Singleton1 getSingleton1·(){
return sing;
}
}
方法二:该方法与第一种方法相比,可以在类加载的时候,不用创建类型对象,不用分配额外的内存。只是在第一次调用的时候才会创建对象,避免类被加载了之后,却不用他,造成资源浪费。
public class Singleton2{
private static Singleton2 sing;
private Singleton2(){}
public static Singleton2 getSinleton2(){
if(sing==null){
sing=new Singleton2();
}
return sing;
}
}
方法三:之前的两种方式都存在线程安全问题,当多线程访问的时候,可能会发生。通过在方法上加锁。因为是静态方法,所以加锁的对象是类对象Singleton3.class.
public class singleton3{
private static Singleton3 sing;
private Singleton3(){}
public synchronized static Singleton3 getSingleton3(){
if(sing=null){
sing=new Singleton3();
}
return sing;
}
}
方法四:相对于方法三,方法四的性能免现提高了。因为方法三的并发时,都需要一个一个等,无论对象是否获得实例。而该方法通过代码块锁的方式,进行双重判断,如果对象已经获得锁,那么就可以直接返回,不用进行 更深一步的操作。而且用了修饰词valitile(他可以保证,多线程在获取变量时是从主内存获得的,而不是从运行的线程的工作内存中获得的。valitile既有synchroized的可见性,但是没有synchronized的并发正确性。但是他可以保证每次线程获取到的都是变量的最新值。
public class Singleton4{
private static valitile Singleton4 sing;
private Singleton4(){}
public static Singleton4 getSingleton4(){
if(sing==null){
synchronized(Singleton4.Class){
if(sing==null){
sing=new Singleton4();
` }
}
}
return sing;
}
}
方法五:通过将对象的创建放在内部类里面,而且通过final修饰词的方式,既可以线程安全,又可以保证在类加载的时候,不创建对象而是在调用方法的时候通过内部类来创建。比前面几种更简洁使用。
poublic class Singleton5{
private Singleton5(){}
private static class inner{
private static final Singleton5 sin=new Singleton5();
}
private static Singleton5 getSingleton5(){
return inner.sin;
}
}
当然除了上面的几种方法,还可以通过枚举获得。