单例模式的特点
- 单例类只能有一个实例
- 单例类必须自己创建自己的唯一实例
- 单例类必须给所有其它对象提供这一实例
写单例模式需要注意的问题:
- 线程安全,多线程环境下不能产生多个实例
实现单例模式的几种方式
1.饿汉模式
public class Singleton1 {
//构造函数私有化
private Singleton1() {}
private static Singleton1 single = new Singleton1();
//静态工厂方法
public static Singleton1 getInstance() {
return single;
}
}
饿汉模式在类加载初始化时就创建好一个静态的对象共外部使用,是线程安全的。
通过将构造方法设置为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。(实际上可以通过反射机智实例化构造方法为private的类的,在次不做考虑)
2.懒汉模式
public class Singleton2 {
//私有构造方法
private Singleton2() {}
private static Singleton2 single = null;
public static Singleton2 getInstance() {
if(single == null) {
single = new Singleton2();
}
return single;
}
}
懒汉模式是在第一次请求单例实例时,才生成实例对象。但上述写法在多线程下不是线程安全的,有可能产生多个single对象
线程安全但低效的版本。
public class Singleton3 {
//私有构造方法
private Singleton3() {}
private static Singleton3 single = null;
public class Singleton3 getInstance() {
synchronized(Singleton3.class) {
if(single == null) {
single = new Singleton3();
}
}
return single;
}
}
这种方式实现了线程安全,但是效率低下,每次获取单例对象都要等待其它线程释放锁。
双重检查版本
public class Singleton4 {
private Singleton4() {}
private static Singleton4 single = null;
//双重检查
public static Singleton4 getInstance() {
if(single == null) {
synchronized (Singleton4.class) {
if(single == null) {
single = new Singleton4();
}
}
}
return single;
}
}
这样只在第一次创建单例对象时,线程之间才会去竞争锁。之后就不会再竞争了。同时使用了第二次检查,这样也就避免了对象多次被创建。
3.静态内部类实现
public class Singleton6 {
//私有构造
private Singleton6() {}
//静态内部类
private static class InnerObject {
private static Singleton6 single = new Singleton6();
}
public static Singleton6 getInstance() {
return InnerObject.single;
}
}
线程安全,懒汉。
网友评论