首先最简单的两种,也是单例模式最原生的两种实现是饿汉式和懒汉式:
1.饿汉式:
public class SingletonObject1 { /** * 1.线程安全,调用效率高,无法懒加载,即初始化的时候,就已经被实例化了,可能造成资源的浪费,故不推荐 */ private static final SingletonObject1 instance = new SingletonObject1(); private SingletonObject1() { //empty } public static SingletonObject1 getInstance() { return instance; } }
2.懒汉式:
public class SingletonObject2 { /** * 2.线程不安全,调用效率高,延迟加载 */ private static SingletonObject2 instance; private SingletonObject2(){ //empty } public static SingletonObject2 getInstance(){ if(instance == null){ instance = new SingletonObject2(); } return SingletonObject2.instance; } }
3.添加synchronized加锁的懒汉式单例
public class SingletonObject3 { /** * 线程安全,调用效率低,延迟加载 。因为每次获得实例对象时,都要先进行加锁操作,故效率低 */ private static SingletonObject3 instance; private SingletonObject3(){ //empty } public static synchronized SingletonObject3 getInstance(){ if(instance == null){ instance = new SingletonObject3(); } return SingletonObject3.instance; } }
4.DoubleCheck双重锁判断机制
public class SingletonObject4 { /** * 在加锁前新进行是否为空的判断,提高调用效率,但因为JVM底层模型,创建一个对象是先开辟堆空间,再进行对象初始化,可能在此过程中由于并发问题对象没初始化完毕直接引用,出现空指针 */ private static SingletonObject4 instance; private SingletonObject4(){ //empty } public static SingletonObject4 getInstance(){ if(instance == null){ synchronized (SingletonObject2.class){ if(instance == null){ instance = new SingletonObject4(); } } } return SingletonObject4.instance; } }
5. 双重锁机制的改进
/** * 懒加载,加入volatile关键字,强制其对象初始化完毕后才能进行被调用 */ private static volatile SingletonObject4 instance; private SingletonObject4(){ //empty } public static SingletonObject4 getInstance(){ if(instance == null){ synchronized (SingletonObject2.class){ if(instance == null){ instance = new SingletonObject4(); } } } return SingletonObject4.instance; } }
6.静态内部类实现方式,推荐使用
public class SingletonObject6 { /** * (线程安全,调用效率高,可以延时加载) */ private SingletonObject6(){ } private static class InstanceHolder{ private final static SingletonObject6 instance = new SingletonObject6(); } public static SingletonObject6 getInstance(){ return InstanceHolder.instance; } }
7.枚举方式(可以防止反射方式获取其实例,同时也不会被反实例化)
public enum SingletonObject8 { INSTANCE; public void dosomething(){ } }
如下·代码是通过借用枚举来实现单例,即验证枚举本身是单例的,实例只会被初始化一次。
public class SingletonObject7 { private SingletonObject7() { } private enum Singleton { INSTANCE; private final SingletonObject7 instance; Singleton() { instance = new SingletonObject7(); } public SingletonObject7 getInstance() { return instance; } } public static SingletonObject7 getInstance() { return Singleton.INSTANCE.getInstance(); } public static void main(String[] args) { MyThread my = new MyThread(); Thread t= new Thread(my); t.start(); } }
class MyThread implements Runnable{ int i = 0; @Override public void run() { while(i<1000) System.out.println("=======================>>>>>>>"+SingletonObject7.getInstance()); i++; } }