实现单例的几种常见方式及特点分析
- 1.懒汉式,线程安全,直接创建对象,然后判断是否为空
public class Test {
/**
* 单例模式,懒汉式,线程安全 final限定实例不可再改变
* 特点:实现方式简单
*/
public static class Singleton1 {
private final static Singleton1 INSTANCE = new Singleton1();
private Singleton1() {
}
public static Singleton1 getInstance() {
return INSTANCE;
}
}
- 2.懒汉式,线程不安全,只适合单线程,很费时间
/**
* 特点:懒汉式,线程不安全
* 缺陷:如果两个线程同时运行到判断instance是否为null的if语句,并且instance没被创建时,那么两个线程都会创建一个实例,就不再满足单例模式的要求了。
*/
public static class Singleton2 {
private static Singleton2 instance = null;
private Singleton2() {
}
public static Singleton2 getInstance() {
if (instance == null) {
instance = new Singleton2();
}
return instance;
}
}
- 3.饿汉式,线程安全,多线程环境下效率不高
/**
* 单例模式,饿汉式,线程安全,多线程环境下效率不高,加同步锁
* 缺陷:获取实例的方法中添加了同步锁,会降低获取实例的效率,
* 假设当instance已经被创建过了,即不为空的情况下,这种方式还会先加同步锁,再判断instance是否为空,这是没有必要的,也就是读取instance是不需要处理并发读操作可能带来的问题。
*/
public static class Singleton3 {
private static Singleton3 instance = null;
private Singleton3() {
}
public static synchronized Singleton3 getInstance() {
if (instance == null) {
instance = new Singleton3();
}
return instance;
}
}
- 4.懒汉式的变形,线程安全
/**
* 单例模式,懒汉式,变形,线程安全,static代码中创建实例
* 特点:static会在类被加载时编译,所以只要类被载入内存编译,那么instance肯定就被创建了,这样减少了判断和加锁的操作。
*/
public static class Singleton4 {
private static Singleton4 instance = null;
static {
instance = new Singleton4();
}
private Singleton4() {
}
public static Singleton4 getInstance() {
return instance;
}
}
懒汉式和饿汉式单例的区别:
- 懒汉式是以空间换时间,饿汉式是时间换空间
懒汉式在多线程环境下可能创建多个对象
5.使用静态内部类,线程安全,推荐使用
/**
* 单例模式,使用静态内部类,线程安全(推荐)
*/
public static class Singleton5 {
private final static class SingletonHolder {
private static final Singleton5 INSTANCE = new Singleton5();
}
private static Singleton5 getInstance() {
return SingletonHolder.INSTANCE;
}
}
- 6.静态内部类,使用枚举方式,线程安全,推荐使用
/**
* 静态内部类,使用枚举方式,线程安全(推荐)
*/
public enum Singleton6 {
INSTANCE;
public void whateverMethod() {
}
}
- 7.静态内部类,使用双重校验锁(volatile和synchronized),线程安全,推荐使用
/**
* 静态内部类,使用双重校验锁,线程安全(推荐)
*/
public static class Singleton7 {
private volatile static Singleton7 instance = null;
private Singleton7() {
}
public static Singleton7 getInstance() {
if (instance == null) {
synchronized (Singleton7.class) {
if (instance == null) {
instance = new Singleton7();
}
}
}
return instance;
}
}
}
- 类似Spring里面的方法,将类名注册,下次从里面直接获取
import java.util.HashMap;
import java.util.Map;
//类似Spring里面的方法,将类名注册,下次从里面直接获取。
public class Singleton3 {
private static Map<String, Singleton3> map = new HashMap<String, Singleton3>();
static {
Singleton3 single = new Singleton3();
//编译时反射
map.put(single.getClass().getName(), single);
}
// 保护的默认构造子
protected Singleton3() {
}
// 静态工厂方法,返还此类惟一的实例
public static Singleton3 getInstance(String name) {
if (name == null) {
name = Singleton3.class.getName();
System.out.println("name == null" + "--->name=" + name);
}
if (map.get(name) == null) {
try {
map.put(name, (Singleton3) Class.forName(name).newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return map.get(name);
}
// 一个示意性的商业方法
public String about() {
return "Hello, I am RegSingleton.";
}
public static void main(String[] args) {
Singleton3 single3 = Singleton3.getInstance(null);
System.out.println(single3.about());
}
}