单例模式,顾名思义就是只有一个实例,创建单例模式的步骤:
1私有构造方法,目的是不让程序随意创建对象。
2提供一个公共的静态方法,获取当前类的对象。因为私有化构造方法后,其他类就不能通过new创建该类对象了,所以只能通过类名.方法获取对象,所以方法为公共静态的。
3提供一个私有成员变量,就是本身的对象。
单例模式常见的分为两种情况,饿汉式和懒汉式,饿汉式,懒汉式中的饿、懒是指创建对象的时机不同。
其它方式还有双重检测锁,静态内部类,枚举。
饿汉式:是指在随着类的加载而创建对象。优点是调用效率高,线程安全(类加载这一过程是天然线程安全的过程),缺点是不支持延迟加载,资源利用率低。
public class Singleton {
private Singleton(){
}
private static Singleton s=new Singleton();
public static Singleton getInstance(){
return s;
}
}
懒汉式:是指在调用方法时创建对象。优点是支持延迟加载,资源利用率高,缺点是线程不安全,调用效率低。
public class Singleton2 {
private Singleton2(){
}
private static Singleton2 s=null;
public static Singleton2 getInstance(){
if(s==null){
s=new Singleton2();
}
return s;
}
}
下面是懒汉式的线程安全版本。
public class Singleton2 {
private Singleton2(){
}
private static Singleton2 s=null;
public static synchronized Singleton2 getInstance(){
if(s==null){
s=new Singleton2();
}
return s;
}
}
下面是双重锁模式,既保证了安全,又保证了效率,其实就是把同步下发到if里面。但是由于JVM底层实现的原因,该方法可能会出错,不建议这么使用。
public class Singleton3 {
private Singleton3() {
}
private volatile static Singleton3 s = null;
public static Singleton3 getInstance() {
if (s == null) {//该if条件是为了提高程序效率,假如s不为空就不用进入同步。直接返回对象
synchronized (Singleton3.class) {//该处加同步,保证多线程情况下,对象的唯一
if (s == null) {
s = new Singleton3();
}
}
}
return s;
}
静态内部类,该方法支持延迟加载,线程安全,调用效率高。
public class Singleton4 {
private Singleton4(){
}
private static class Inner{
private static final Singleton4 instance=new Singleton4();
}
public static Singleton4 getInstance(){
return Inner.instance;
}
}
但是以上实现单例的方式,都存在一些问题,比如通过反射或者反序列化都可以创建多个对象,破坏了单例的初衷。可以外加一些判断条件或者枚举方式实现单例来克服这些问题。