首页 > 编程语言 > 详细

JAVA 单例模式总结

时间:2021-07-06 23:28:28      阅读:26      评论:0      收藏:0      [点我收藏+]

1.单列模式

1.手写单例模式 2.线程安全的单例模式

什么是单例模式?

单例类在整个程序中只能有一个实例,这个类负责创建自己的对象,并确保只有一个对象被创建。

在什么情况下使用单例?一般全局使用的类写成单例,会消耗许多系统资源的类写成单例(数据库连接池、工厂类、数据源、sping bean的作用域等)(创建销毁都需要消耗许多系统资源)。

代码实现要点 a) 私有化构造方法 b) 持有该类的属性(创建对象) c) 对外提供获取对象的静态方法

1)饿汉式是典型的单例模式(没有加锁),通过JAVA的类加载机制实现。类加载机制默认是线程安全的,类加载成功,静态属性被初始化,即对象初始化是无延迟的。 饿汉式:线程安全、反射不安全、反序列化不安全(添加readResolve()方法可以保证反序列化安全)

/*
饿汉式
*/
public class Singleton1
{
   private Singleton1()//私有化构造方法
  {}
   private static Singleton1 instance= new Singleton1();//当前类的属性(静态可以全局应用)
?
   public static Singleton1 getInstance()//对外提供获取对象的静态方法
  {
       return instance;
  }
}

2)登记式:线程安全、防止反射攻击、反序列化不安全(添加readResolve()方法可以保证反序列化安全)

延迟初始化

/*
登记式
*/
public class Singleton2
{
   private Singleton2()//私有化构造方法
  {
       if(SingletonHolder.instance != null)
      {
           throw new IllegalStateException();  //若静态内部类方法不为空则抛出状态异常
      }
  }
?
   private static class SingletonHolder{
       private static Singleton2 instance = new Singleton2(); //静态内部类
  }
?
   public static Singleton2 getInstance()
  {
       return SingletonHolder.instance;   //对外提供获取对象的静态方法
  }
?
}

3)枚举式:线程安全、反射安全(没有构造方法)、反序列化安全

/*
枚举式
*/
public enum  Singleton3
{
   INSTANCE //枚举中的对象实现方法
          {
               protected void doSomething()
              {
                   System.out.println("doSomething");
              }
          };
           protected abstract void doSomething();
}

4)懒汉式

/*
懒汉式 同步方法
*/
public class Singleton4
{
   private Singleton4()  //私有化构造方法
  {}
   private static Singleton4 instance = null;  //持有当前类的属性
?
   public static synchronized Singleton4 getInstance()  //对外提供获取对象的静态方法
  {
       if(instance == null)
      {
           instance =new Singleton4();
      }
       return instance;
  }
}

 

/*
懒汉式   同步代码块
*/
public class Singleton4
{
   private Singleton4()  //私有化构造方法
  {
  }
?
   private static Singleton4 instance = null;  //持有当前类的属性
?
   public static Singleton4 getInstance()  //对外提供获取对象的静态方法
  {
       synchronized (Singleton4.class)
      {
           if (instance == null)
          {
               instance = new Singleton4();
          }
           return instance;
      }
  }
}

5)双重检锁

/*
  双重检锁
*/
public class Singleton5
{
   private Singleton5()  //私有化构造方法
  {
  }
//双检锁加volatile关键字解决指令重排
   private static volatile Singleton5 instance = null;  //持有当前类的属性
?
   public static Singleton5 getInstance()  //对外提供获取对象的静态方法
  {
       if (instance == null)//双重检锁 效率高
      {
           synchronized (Singleton5.class)
          {
               if (instance == null)
              {
                   instance = new Singleton5();
              }
?
          }
      }
       return instance;
  }
?
}
/*instance=new Singleton5()会执行如下操作:
(1)分配对象内存空间
(2)初始化对象
(3)instance指向(1)中分配的空间
?
在某些编译器上,可能会出现指令重排:
(1)分配对象内存空间
(2)instance指向(1)中分配的空间(但此时对象没有初始化)
(3)初始化对象
?
解决方法:在当前对象前加volatile关键字,确保不出现指令重排
*/

6)ThreadLocal

ThreadLocal:不加锁,以空间换时间,为每个线程提供变量的独立副本

/*
TreadLocal   只能保证一个线程内是单例的(即一个线程同时获取多个对象是同一对象) 不能保证多个线程间是单例的
*/
public class Singleton6
{
   private Singleton6()
  {
  }
?
   private static Singleton6 instance = null;  //延时创建对象
?
   private static final ThreadLocal<Singleton6> thread = new ThreadLocal<Singleton6>()
  {
       @Override
       protected Singleton6 initialValue() //重写初始化方法
      {
           return new Singleton6();
      }
  };
?
   public static Singleton6 getInstance()
  {
       return thread.get();
  }
}

7)CAS( Compare-and-Swap)

无锁的乐观策略:假设进程访问资源不会产生冲突,如果出现冲突就重试当前的操作

/*
CAS  
*/
public class Singleton7
{
   private Singleton7()
  {
  }
?
   //原子类的封装
   private static final AtomicReference<Singleton7> instance = new AtomicReference<Singleton7>();
?
   public static final Singleton7 getInstance()
  {
       for (; ; )//线程重试
      {
           Singleton7 current = instance.get();//拿到原子类引用instance指向的对象current
           if (current != null)
          {
               return current;  //判断current指向对象是否为null,非null返回
          }
           current = new Singleton7(); //为null就创建对象 (延时加载)
           if (instance.compareAndSet(null, current))//调用原子类的compareAndSet方法进行判断
          {                                              
               return current; //如果此时instance指向是null,则用current替换instance
          }
      }
  }
}

 

JAVA 单例模式总结

原文:https://www.cnblogs.com/hkz329/p/14979036.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!