概述:单例模式就是在整个软件系统中,对于某个类只能存在一个对象实例,而且只提供了一个获取该对象实例的方法(静态方法)
1)单例模式一共有8种实现的方式
①饿汉式(静态常量)
②饿汉式(静态代码块)
③懒汉式(线程不安全)
④懒汉式(线程安全:同步方法)
⑤懒汉式(线程安全:同步代码块)
⑥双重检查
⑦静态内部类
⑧枚举

一 饿汉式(静态变量)

优点:写法简单,在类装载的时候就已经完成了实例化,避免了线程安全问题
缺点:在装载的时候完成了实例化,没有达到懒加载的效果,如果自始至终都没有使用过整个对象,则会造成内存浪费

  1. public class Single1 {
  2. // 初始创建唯一的对象实例
  3. private Single1 instance = new Single1();
  4. // 构造器私有化
  5. private Single1(){}
  6. // 公共方法,返回单例对象
  7. public Single1 getInstance() {
  8. return instance;
  9. }
  10. }

二 饿汉式(静态代码块)

这种方式和上一个实现类似,也是在类装载的时候进行对象的实例化过程,但是把这过程放在了静态代码块里头
结论:可用,也可能造成内存的浪费

  1. public class Single2 {
  2. // 1、私有化构造器
  3. private Single2() {
  4. }
  5. // 2、静态变量
  6. private static Single2 instance;
  7. static {
  8. instance = new Single2();
  9. }
  10. // 3、公共方法
  11. public static Single2 getInstance() {
  12. return instance;
  13. }
  14. }

三 懒汉式(线程不安全)

在需要获取对象时,才去判断内存中是否已经存在此对象

优点:起到了懒加载的效果,但是只能在单线程下使用
缺点:在多线程的情况下,容易会生成多个对象实例,线程不安全
总结:在实际开发中,不要使用

  1. public class Single3 {
  2. private static Single3 instance;
  3. private Single3() {
  4. }
  5. public static Single3 getInstance() {
  6. if (instance == null) {
  7. instance = new Single3();
  8. }
  9. return instance;
  10. }
  11. }

四 懒汉式(线程安全:同步方法)

给方法加锁确实是解决了线程安全问题,但是又引发了另一个问题:效率低下,因为每一个人想使用这个方法,都要去判断是否握有这个锁,如果当前有人不释放锁,则需要等待
总结:在开发中,也不推荐使用

  1. public class Single4 {
  2. private static SIngle4 instance;
  3. private SIngle4() {
  4. }
  5. //在方法加锁,只有握有此锁的对象才能进入
  6. public static synchronized SIngle4 getInstance() {
  7. if (instance == null) {
  8. instance = new SIngle4();
  9. }
  10. return instance;
  11. }
  12. }

五 懒汉式(线程安全:同步代码块)

这是对上一种方法的改进,效率高一些

  1. public class Single5 {
  2. private static SIngle5 instance;
  3. private SIngle5() {
  4. }
  5. public static SIngle5 getInstance() {
  6. if (instance == null) {
  7. // 同步代码块,锁为类
  8. // 为什么同步代码块中还需要判断呢,因为以防外一,
  9. // 有两个人同时第一时间都需要创建对象,而此时则需要判断
  10. synchronized (SIngle5.class) {
  11. if (instance==null){
  12. instance = new SIngle5();
  13. }
  14. }
  15. }
  16. return instance;
  17. }
  18. }

六 双重检查

  1. public class Single5 {
  2. private static SIngle5 instance;
  3. private SIngle5() {
  4. }
  5. public static SIngle5 getInstance() {
  6. if (instance == null) {
  7. // 同步代码块,锁为类
  8. // 为什么同步代码块中还需要判断呢,因为以防外一,
  9. // 有两个人同时第一时间都需要创建对象,而此时则需要判断
  10. synchronized (SIngle5.class) {
  11. if (instance==null){
  12. instance = new SIngle5();
  13. }
  14. }
  15. }
  16. return instance;
  17. }
  18. }

七 静态内部类

这种方式采用类装载的机制来保证初始化时只有一个线程
静态内部类 Singleton 在 SIngle7 装载的时候并不会立即实例化,而是在需要时,调用getInstance 方法才会装载
类的静态属性保证了只会在第一次的加载类的时候初始化,jvm帮助保证了线程的安全,在类进行初始化时,其他线程时无法进入的
总结:线程安全,实现了懒加载,效率高,推荐使用

  1. public class Single7 {
  2. private static SIngle7 instance;
  3. private SIngle7() {
  4. }
  5. //静态内部类,有一个静态属性
  6. private static class Singleton {
  7. private static final SIngle7 INSTANCE = new SIngle7();
  8. }
  9. //静态方法,直接返回静态内部类的属性
  10. public static SIngle7 getInstance() {
  11. return Singleton.INSTANCE;
  12. }
  13. }

八 枚举

使用枚举,可以实现单例,这是JDK5新增的实现方式
不仅能避免线程同步问题,而且还能防止反序列化重新创建新的对象
这是 Effective Java 作者提倡的方法

public enum  Single8 {
    INSTANCE;
}