|
单例设计模式
释义
单例模式,采取一定的方法保证整个上下文中某个类只能存在一个实例对象,并且该类只提供一个取得其对象实例的静态方法。典型的例子是MyBatis中的SqlSessionFactory负责创建SqlSession对象,在MyBatis框架中,SqlSessionFactory是重量级的(需要加载很多配置),它的创建和销毁都比较消耗资源,因此,将它构建为单例可以提升性能。
实现步骤
· 构造器私有。
· 提供静态属性,赋予单例对象。
· 提供静态方法,返回实例对象。
示例代码
需要注意的是单例模式有两种写法,分别是懒汉式和饿汉式,同时需要确保对象是线程安全的,这样才满足单例的要求,以下提供几种实现方式。
饿汉式(静态常量)
public class SingletonTest1 {
public static void main(String[] args) {
Singleton1 instance1 = Singleton1.getInstance();
Singleton1 instance2 = Singleton1.getInstance();
System.out.printf("相同对象? %s", instance1 == instance2);
}
}
class Singleton1 {
private Singleton1() {}
private static final Singleton1 instance = new Singleton1();
public static Singleton1 getInstance() {
return instance;
}
}
· 优点:无线程安全问题。
· 缺点:类加载时即分配内存空间,提前占用内存。
饿汉式(静态代码块)
public class SingletonTest2 {
public static void main(String[] args) {
Singleton2 instance1 = Singleton2.getInstance();
Singleton2 instance2 = Singleton2.getInstance();
System.out.printf("相同对象? %s", instance1 == instance2);
}
}
class Singleton2 {
private Singleton2() {}
private static final Singleton2 instance;
static {
instance = new Singleton2();
}
public static Singleton2 getInstance() {
return instance;
}
}
饿汉式(枚举)
public class SingletonTest7 {
public static void main(String[] args) {
Singleton7 instance1 = Singleton7.getInstance();
Singleton7 instance2 = Singleton7.getInstance();
System.out.printf("相同对象? %s", instance1 == instance2);
}
}
enum Singleton7 {
//默认就是单例对象
INSTANCE;
public static Singleton7 getInstance() {
return INSTANCE;
}
}
· 枚举默认就是单例的。
懒汉式(静态常量)
public class SingletonTest3 {
public static void main(String[] args) {
Singleton3 instance1 = Singleton3.getInstance();
Singleton3 instance2 = Singleton3.getInstance();
System.out.printf("相同对象? %s", instance1 == instance2);
}
}
class Singleton3 {
private Singleton3() {}
private static Singleton3 instance;
public static Singleton3 getInstance() {
if (instance == null) {
instance = new Singleton3();
}
return instance;
}
}
· 缺点:存在线程安全问题。
懒汉式(同步方法)
public class SingletonTest4 {
public static void main(String[] args) {
Singleton4 instance1 = Singleton4.getInstance();
Singleton4 instance2 = Singleton4.getInstance();
System.out.printf("相同对象? %s", instance1 == instance2);
}
}
class Singleton4 {
private Singleton4() {}
private static Singleton4 instance;
public static synchronized Singleton4 getInstance() {
if (instance == null) {
instance = new Singleton4();
}
return instance;
}
}
· 优点:线程安全。
· 缺点:效率低。
<hr/>懒汉式(双重检查)(推荐)
public class SingletonTest5 {
public static void main(String[] args) {
Singleton5 instance1 = Singleton5.getInstance();
Singleton5 instance2 = Singleton5.getInstance();
System.out.printf(&#34;相同对象? %s&#34;, instance1 == instance2);
}
}
class Singleton5 {
private Singleton5() {}
//必须使用volatile关键字,具体含义参见补充说明
private static volatile Singleton5 instance;
public static Singleton5 getInstance() {
if (instance == null) {
synchronized (Singleton5.class) {
//马上更新instance的值
if (instance == null) instance = new Singleton5();
}
}
return instance;
}
}
· 优点:线程安全,节省内存。
懒汉式(静态内部类)(推荐)
public class SingletonTest6 {
public static void main(String[] args) {
Singleton6 instance1 = Singleton6.getInstance();
Singleton6 instance2 = Singleton6.getInstance();
System.out.printf(&#34;相同对象? %s&#34;, instance1 == instance2);
}
}
class Singleton6 {
private Singleton6() {}
//静态内部类特点: 当Singleton6加载时默认不会加载Singleton6Instance
private static class Singleton6Instance {
private static final Singleton6 instance = new Singleton6();
}
public static Singleton6 getInstance() {
return Singleton6Instance.instance;
}
}
· 优点:线程安全,节省内存。
<hr/>补充说明
关于volatile关键字,使用volatile修饰成员变量或静态成员变量将使变量具备两层含义,分别是:
· 保证不同线程之间该变量值的可见性,即当某个线程修改了此变量的值后,另一线程立即可见。
· 禁止指令重排序。
什么是指令重排序:
· 当程序运行到volatile变量的读操作或写操作时,在其前面的操作肯定已经全部执行,在其后面的操作肯定还未执行,且该变量值对后面操作立即可见。
· JVM进行指令优化时,不能将在正在访问volatile修饰的变量的语句放在其后面执行,反之也不能把volatile修饰的变量后面的语句放到其前面执行。
欢迎留言交流,欢迎转载,转载请注明出处即可,谢谢大家。。。 |
|