单例
单例的目的是确保一个类只有一个实例,并提供该实例的全局访问点。
- [类]
使用一个私有构造函数、一个私有静态变量以及一个公有静态函数来实现。私有构造函数保证了不能通过构造函数来创建对象实例,只能通过公有静态函数返回唯一的私有静态变量。
懒汉式-线程不安全
懒汉式-单例,静态变量被延迟实例化,这样做的好处是节约资源,但是在多线程下,因为多线程同时进入if (uniqueInstance == null) ,并且此时 uniqueInstance 为 null,那么会有多个线程执行uniqueInstance = new Singleton(); 语句,这将导致实例化多次 uniqueInstance。
public class Singleton {
private static Singleton unqueInstance = null;
//私有构造函数
private Singleton(){
}
public static Singleton getUnqueInstance(){
if(unqueInstance==null){
unqueInstance = new Singleton();
}
return unqueInstance;
}
}
懒汉式-线程安全
线程不安全的原因是多个线程同时进入了共有静态函数中的if代码块里,所以只要在共有静态函数上加一个同步锁就可以防止这样的情况。
public class Singleton {
private static Singleton unqueInstance = null;
//私有构造函数
private Singleton(){
}
public static synchronized Singleton getUnqueInstance(){
if(unqueInstance==null){
unqueInstance = new Singleton();
}
return unqueInstance;
}
}
但是其实这样笼统的修改会影响效率的问题,比如当unqueInstance不等于null的时候,应该直接返回,但是此时unqueInstance==null和unqueInstance!=null同时访问该方法,这会让线程阻塞时间过长,因此该方法有性能问题。
饿汉式-线程安全
public class Singleton {
private static Singleton unqueInstance = new Singleton();
//私有构造函数
private Singleton(){
}
public static Singleton getUnqueInstance(){
return unqueInstance;
}
}
直接实例化的方式也丢失了延迟实例化带来的节约资源的好处。
双重校验锁-线程安全
这个是对懒汉式线程安全的进一步改进,就像我们在之前的描述一样,线程不安全的原因是多个线程同时进入了共有静态函数中的if代码块里,我们只需要对if代码块加入同步锁,但是如果两个线程都执行了 if 语句,那么两个线程都会进入 if 语句块内。虽然在 if 语句块内有加锁操作,但是两个线程都会执行 uniqueInstance = new Singleton(); 这条语句,只是先后的问题,那么就会进行两次实例化。因此必须使用双重校验锁,也就是需要使用两个 if 语句。
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getUniqueInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
静态内部类实现
当 Singleton 类加载时,静态内部类 SingletonHolder 没有被加载进内存。只有当调用 getUniqueInstance() 方法从而触发 SingletonHolder.INSTANCE 时 SingletonHolder 才会被加载,此时初始化 INSTANCE 实例,并且 JVM 能确保 INSTANCE 只被实例化一次。
这种方式不仅具有延迟初始化的好处,而且由 JVM 提供了对线程安全的支持。
public class Singleton {
private Singleton(){
}
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getUniqueInstance(){
return SingletonHolder.INSTANCE;
}
}
枚举实现
public enum Singleton {
INSTANCE;
private String objName;
public String getObjName() {
return objName;
}
public void setObjName(String objName) {
this.objName = objName;
}
public static void main(String[] args) {
// 单例测试
Singleton firstSingleton = Singleton.INSTANCE;
firstSingleton.setObjName("firstName");
System.out.println(firstSingleton.getObjName());
Singleton secondSingleton = Singleton.INSTANCE;
secondSingleton.setObjName("secondName");
System.out.println(firstSingleton.getObjName());
System.out.println(secondSingleton.getObjName());
// 反射获取实例测试
try {
Singleton[] enumConstants = Singleton.class.getEnumConstants();
for (Singleton enumConstant : enumConstants) {
System.out.println(enumConstant.getObjName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}