1、饿汉式
public class Hungary {
private final static Hungary HUNGARY = new Hungary();
public static Hungary getInstance() {
return HUNGARY;
}
public static void main( String[] args ) {
Hungary instance1 = Hungary.getInstance();
Hungary instance2 = Hungary.getInstance();
System.out.println(instance1);
System.out.println(instance2);
}
}
- 优点:
- 在类加载的同时已经创建好一个静态对象,调用时反应速度快;典型的空间换时间,当类装载的时候就会创建类实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断了,节省了运行时间。
- 不存在线程安全问题;因为虚拟机保证只会装载一次,在装载类的时候是不会发生并发的
- 缺点:
- 资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化
2、懒汉式
public class LazyMan {
private static LazyMan lazyMan;
public static LazyMan getInstance() {
if (lazyMan == null) {
lazyMan = new LazyMan();
}
return lazyMan;
}
}
- 优点
- 资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法
- 缺点
- 多线程下并发不安全
2.1、懒汉式改进(解决并发问题)
public class LazyMan {
private static LazyMan lazyMan;
public synchronized static LazyMan getInstance() {
if (lazyMan == null) {
lazyMan = new LazyMan();
}
return lazyMan;
}
}
- 缺点: 第一次加载时不够快,多线程使用不必要的同步开销大
2.2、懒汉式改进(双重检测)
public class LazyMan {
private static LazyMan lazyMan;
public static LazyMan getInstance() {
if (lazyMan == null) {
synchronized (LazyMan.class){
if(lazyMan == null){
lazyMan = new LazyMan();
}
}
}
return lazyMan;
}
}
- 缺点: 第一次加载时反应不快,由于指令重排,会造成失败
- 在堆中开辟对象所需空间,分配地址
- 根据类加载的初始化顺序进行初始化
- 将内存地址返回给栈中的引用变量
2.3、懒汉式改进(双重检测改进volatile)
public class LazyMan {
private static volatile LazyMan lazyMan;
public static LazyMan getInstance() {
if (lazyMan == null) {
synchronized (LazyMan.class){
if(lazyMan == null){
lazyMan = new LazyMan();
}
}
}
return lazyMan;
}
}
2.4、懒汉式改进(防止部分反射破坏)
public class LazyMan {
private static LazyMan lazyMan;
private LazyMan() {
synchronized (LazyMan.class) {
if (lazyMan!=null){
throw new RuntimeException("不要试图使用反射破坏异常");
}
}
}
public static LazyMan getInstance() {
if (lazyMan == null) {
synchronized (LazyMan.class) {
if (lazyMan == null) {
lazyMan = new LazyMan();
}
}
}
return lazyMan;
}
public static void main( String[] args ) throws Exception {
Constructor<LazyMan1> declaredConstructor = LazyMan1.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan1 instance = LazyMan1.getInstance();
LazyMan1 instance2 = declaredConstructor.newInstance();
System.out.println(instance);
System.out.println(instance2);
}
}
- 缺点:只有先创建对象,再使用反射破坏时才起作用;如果使用反射创建对象,无效。
2.5、懒汉式改进(防止部分反射破坏,2.4改进)
public class LazyMan {
private static boolean isCreate = false;
private LazyMan() {
synchronized (LazyMan.class) {
if (isCreate == false) {
isCreate = true;
} else {
throw new RuntimeException("不要试图使用反射破坏异常");
}
}
}
private static LazyMan lazyMan;
public static LazyMan getInstance() {
if (lazyMan == null) {
synchronized (LazyMan.class) {
if (lazyMan == null) {
lazyMan = new LazyMan();
}
}
}
return lazyMan;
}
}
public static void main(String[] args) throws Exception{
Field flag = LazyMan.class.getDeclaredField("isCreate");
flag.setAccessible(true);
Constructor<LazyMan> declaredConstructor = LazyMan2.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan instance1 = declaredConstructor.newInstance();
System.out.println(instance1);
flag.set(instance1,false);
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance2);
}
2.6、使用枚举防止被破坏
public enum EnumSingleton {
INSTANCE;
public EnumSingleton getInstance(){
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Constructor<EnumSingle> declaredConstructor =
EnumSingle.class.getDeclaredConstructor(String.class,int.class);
declaredConstructor.setAccessible(true);
EnumSingle instance = declaredConstructor.newInstance();
EnumSingle instance2 = declaredConstructor.newInstance();
System.out.println(instance);
System.out.println(instance2);
}
}