单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。选择单例模式就是为了避免不一致状态,避免政出多头。
这里主要介绍:懒汉式单例、饿汉式单例
一、懒汉式单例
public class SingletonPattern {
//私有构造方法避免外部对类实例化
private SingletonPattern() {}
private static SingletonPattern single = null; // 初始化对象为空
// 静态工厂方法
public static SingletonPattern getInstance() {
if (single == null) {
// 第一次调用为空的时候创建实例
single = new SingletonPattern();
}
return single;
}
}
构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,SingletonPattern 的唯一实例只能通过getInstance()方法访问。
但是上述单例模式没有考虑线程问题,并发环境下可能出现多个实例,下面这几种解决线程安全问题:
1.synchronized 同步
public class SingletonPattern {
//私有构造方法避免外部对类实例化
private SingletonPattern() {}
private static SingletonPattern single = null; // 初始化对象为空
// 静态工厂方法
public static synchronized SingletonPattern getInstance() {
if (single == null) {
single = new SingletonPattern();
}
return single;
}
}
synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。
虽然线程安全了,但是每次都要同步,会影响性能
2、双重检查锁定
public class SingletonPattern {
//私有构造方法避免外部对类实例化
private SingletonPattern() {}
private static SingletonPattern single = null; // 初始化对象为空
// 静态工厂方法
public static SingletonPattern getInstance() {
if (single == null) {
synchronized (SingletonPattern.class) {
if (single == null) {
single = new SingletonPattern();
}
}
}
return single;
}
}
3、静态内部类
public class SingletonPattern {
private static class LazyHolder {
private static final SingletonPattern INSTANCE = new SingletonPattern();
}
//private构造方法避免外部实例化
private SingletonPattern() {
}
//因为instance是static的,所以它不会被构造多次
public static final SingletonPattern getInstance() {
return LazyHolder.INSTANCE;
}
}
既实现了线程安全,又避免了同步带来的性能影响。
二、饿汉式单例
public class SingletonPattern {
//private构造方法避免外部实例化
private SingletonPattern() {}
//在类初始化时,已经自行实例化
private static final SingletonPattern single = new SingletonPattern();
//静态工厂方法
public static SingletonPattern getInstance() {
return single;
}
}
饿汉式单例在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变。线程本身式安全的。
三、单例模式实例
这里以饿汉模式为例
public class SingletonPattern {
// private构造方法避免外部实例化
private SingletonPattern() {
}
// 在类初始化时,已经自行实例化
private static final SingletonPattern single = new SingletonPattern();
private String name;
private int age;
// 静态工厂方法
public static SingletonPattern getInstance() {
return single;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "SingletonPattern [name=" + name + ", age=" + age + "]";
}
}
测试类
package single;
public class testSP {
public static void main(String[] args) {
SingletonPattern sp = SingletonPattern.getInstance();
sp.setName("yyy");
sp.setAge(18);
SingletonPattern sp2 = SingletonPattern.getInstance();
sp2.setName("fff");
sp2.setAge(20);
System.out.println(sp);
System.out.println(sp2);
if (sp == sp2) {
System.out.println("sp与sp2是同一实例");
} else {
System.out.println("sp与sp2不是同一实例");
}
}
}
输出结果为:
SingletonPattern [name=fff, age=20]
SingletonPattern [name=fff, age=20]
sp与sp2是同一实例
不管实现何种功能,整个应用程序都会同享一个实例对象。