单例模式
以下均为一个理解,如有错误请请教,谢谢!
单例模式的设计要求:
一个单例模式的类在任何情况下获得的该类对象都应为同一个对象,而使用new关键字必然会创建一个新的对象,因此new关键字不得在类的外部被调用,可以将构造方法设为private实现;
构造方法私有化,必须对外部提供获取对象的手段。
方式1:
public static final Singleton INSTANCE = new Sington();
方式2:
private static final Singleton INSTANCE = new Singleton();
public static Singleton getInstance(){
return INSTANCE;
}
以上方式无法做到复杂对象的构造,可以在静态方法块中初始化对象,假设有一个config.properties的文件在资源文件夹,
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private int a;
private String b;
static {
Properties properties = new Properties();
try {
properties.load(Singleton.class.getClassLoader().getResourceAsStream("config.properties"));
INSTANCE.a = Integer.parseInt(properties.getProperty("a"));
INSTANCE.b = properties.getProperty("b");
} catch (IOException e) {
e.printStackTrace();
}
}
public static Singleton getInstance(){
return INSTANCE;
}
private Singleton(){
}
public int getA() {
return a;
}
public String getB() {
return b;
}
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1==s2);
System.out.println(s1.getA());
System.out.println(s1.getB());
}
}
方式3:
使用枚举类
public enum CommonError {
INSTANCE(10001,"参数为空");
private CommonError(int errorCode,String errorMsg){
this.errorCode= errorCode;
this.errorMsg = errorMsg;
}
int errorCode;
String errorMsg;
public int getErrorCode() {
return errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
}
以上方式均在类加载之初就实例化了单例对象,称为饿汉式,对之相对,有懒汉式的单例模式
懒汉式单例模式会在获取类对象是判断对象是否为第一次加载
public class Singleton{
private static Sington INSTANCE;
private Singleton(){}
public Singleton getInstance(){
if(INSTANCE==null){
INSTANCE = new Singletion();
}
return INSTANCE;
}
}
这样做明显会出现线程安全问题:在处理空值情况时,第二次获取对象请求的非空判断仍为真,导致创建另一个对象,此时两个INSTANCE会出现后创建的将新创建的INSTANCE实例覆盖,而一个对象再覆盖之前已经返回的情况,可以使用synchronized关键字同步对Singleton类的访问
public class Singleton{
private static Sington INSTANCE;
private Singleton(){}
public Singleton getInstance(){
syncronized(Singletion.class){
if(INSTANCE==null){
INSTANCE = new Singletion();
}
return INSTANCE;
}
}
}
如果这样做,每一次访问都要对INSTANCE进行线程同步的非空判断,可以在同步操作外部再套一层非空判断,只为第一次获取单例对象的操作进行同步。
public class Singleton{
private static Sington INSTANCE;
private Singleton(){}
public Singleton getInstance(){
if(INSTANCE==null){
syncronized(Singletion.class){
if(INSTANCE==null){
INSTANCE = new Singletion();
}
}
return INSTANCE;
}
}
}