所谓单例模式,即外界不能创建对象,即外界不能new Object().实现很简单,私有化构造方法即可。(致萌新:平常通过new Xxx()创建对象即使用了类本身的构造方法,而private修饰的内容在类外部无法访问(反射可以暴力访问))
还需要外界能够引用对象,所以在类中仍需构建对象,并通过公共方法分享到外部
分享的都是对同一对象的引用,就叫单例模式。
而根据构建对象的时间问题,又分出饿汉式和懒汉式两种。
不管是否需要,对象都会被创建,这是饿汉式,饿疯了,来者不拒的感觉
package nuc.edu.ls;
public class Singleton {
private static Singleton eagerSingleton=new Singleton();
private Singleton(){
}
public static Singleton getInstance() {
return eagerSingleton;
}
}
而懒汉式,就是表面上的意思,懒得不想动,当需要的时候才会取创建
因为是在公有方法中创建,如果多个线程同时访问的话,可能会创建出多个不同的对象,违背单例模式的原则。所有需要注意线程安全
1.同步锁写法
package nuc.edu.ls;
public class EagerSingleton {
private static EagerSingleton eagerSingleton=null;
private EagerSingleton() {
}
public static synchronized EagerSingleton getInstance() {
if(eagerSingleton==null) {
eagerSingleton=new EagerSingleton();
}
return eagerSingleton;
}
}
这种写法虽然解决了线程安全问题,但同一时刻只有一个线程能获取对象,存在了效率低下的问题
2.双重校验锁写法
package nuc.edu.ls;
public class EagerSingleton2 {
private static volatile EagerSingleton2 eagerSingleton=null;
private EagerSingleton2() {
}
public static EagerSingleton2 getInstance() {
if(eagerSingleton==null) {
synchronized (EagerSingleton2.class) {
if(eagerSingleton==null) {
eagerSingleton=new EagerSingleton2();
}
}
}
return eagerSingleton;
}
}
volatile用法禁止了指令重排序,防止获得未完成初始化的对象。volatile保证了可见性和禁止了指令重排序,有兴趣的小伙伴可以研究研究
3.内部类写法
package nuc.edu.ls;
public class EagerSingleton3 {
private static EagerSingleton3 eagerSingleton=null;
private static class getSingleton{
static final EagerSingleton3 EAGER_SINGLETON3=new EagerSingleton3();
}
private EagerSingleton3() {
}
public static synchronized EagerSingleton3 getInstance() {
return getSingleton.EAGER_SINGLETON3;
}
}
因为只有getInstance可以访问内部类,而对象在访问内部类后被创建(饿汉式的特性,根据JVM类的加载过程得出)。而身为被final修饰的对象,只有第一次才会被创建。而后的n次,根据常量的特性,从常量池获取,而不是开辟新的空间。(单例模式的特性)