1.饿汉模式
public class SingletonEntity2 { // 在类加载的时候创建对象:饿汉模式 public static SingletonEntity2 obj = new SingletonEntity2(); // 构造方法私有化 private SingletonEntity2(){} public static SingletonEntity2 getInstance(){ return obj; } }
2.懒汉模式
public class SingletonEntity { // 静态变量存放在方法区中,类加载的时候赋值,而且只会赋值一次,懒汉模式 public static SingletonEntity obj = null; // 构造方法私有化 private SingletonEntity() {} // 对外提供获取实例的公开的静态的方法 public static SingletonEntity getInstance() { if (obj == null) { obj = new SingletonEntity(); System.out.println("新创建实例"); } System.out.println("直接返回实例"); return obj; } }
3.测试类
public static void main(String[] args) { SingletonEntity obj1 = SingletonEntity.getInstance(); SingletonEntity obj2 = SingletonEntity.getInstance(); System.out.println(obj1 == obj2); // true}
==========================================================================================================================================
懒汉模式不安全性测试:
1.起现成类:
public class RunnableThreadTest implements Runnable { @Override public void run() { SingletonEntity obj = SingletonEntity.getInstance(); System.out.println(Thread.currentThread().getName()+" "+obj); }}
2.测试类:
public class SingletonTest { public static void main(String[] args) { Thread thread1 = new Thread(new RunnableThreadTest()); Thread thread2 = new Thread(new RunnableThreadTest()); thread1.start(); thread2.start(); }}
3.运行结果:
Thread-0 com.beijing.singleton.SingletonEntity@406866f9Thread-1 com.beijing.singleton.SingletonEntity@25eb939e
==========================================================================================================================================
改善结果:推荐使用双检查锁机制
public class SingletonEntity { // 静态变量存放在方法区中,类加载的时候赋值,而且只会赋值一次,懒汉模式 public static volatile SingletonEntity obj = null; // 构造方法私有化 private SingletonEntity() { } // 对外提供获取实例的公开的静态的方法 public static SingletonEntity getInstance() { try { // 双检查所机制 if (obj == null) { synchronized (SingletonEntity.class) { if (obj == null) { Thread.sleep(1000); obj = new SingletonEntity(); } } } } catch (Exception e) { e.printStackTrace(); } return obj; }}
为什么要用volatile修饰instance?原因:在于instance = new SingletonEntity()的时候,在内存中实际上是分3步执行的:1)分配对象的内存空间:memory = allocate();2)初始化对象:ctorInstance(memory);3)指向分配的地址:instance =memory多线程在执行的时候,2 3可能发生重排序。即有可能线程A执行到第3步的时候,读取到instance不为null,就返回。实际上此时还未执行第二部即未初始化。加上volatile就可以避免2 3步重排序来保证线程安全。