单例模式的学习笔记(Java版)

原创 2015年11月19日 12:22:39
  1. 饿汉模式

立即加载的一种模式,使用 static 的属性,在类第一次运行的时候实例化这个类的实例。

public class MyObject {
    private static MyObject myObject = new MyObject();

    private MyObject() {
    }

    // 缺点: 不能有其他实例变量
    // 因为 getInstance 没有加锁,所以可能会出现多线程同步问题
    public static MyObject getInstance() {
        return myObject;
    }
}
  1. 懒汉模式
public class MyObject {
    private static MyObject myObject;

    private MyObject() {
    }

    // 使用的时候才加载
    // 但是这个方法同样没有加锁,所以多线程一样会出现非单例情况
    public static MyObject getInstance() {
        if (null == myObject)
            myObject = new MyObject();

        return myObject;
    }
}

针对懒汉模式出现多个实例的解决方案:

2.1 使用锁 synchronized

public class MyObject {
    private static MyObject myObject;

    private MyObject() {
    }

    public synchronized static MyObject getInstance() {
        if (null == myObject)
            myObject = new MyObject();

        return myObject;
    }
}

这种方式虽然可以解决多线程多对象的烦恼,但是却是比较影响程序运行速度的,于是,进一步优化。

2.2 使用 synchronized 同步代码块

public class MyObject {
    private static MyObject myObject;

    private MyObject() {
    }

    public static MyObject getInstance() {
        synchronized (MyObject.this) {
            if (null == myObject)
                myObject = new MyObject();

            return myObject;
        }
    }
}

这种和2.1 的基本类似,效率也是比较低的,于是进一步做优化。

2.3 使用 synchronized 同步部分代码块
// 宗旨就是,相互独立的可以分别进行实例化,共享资源一定需要加锁使其变成单例。

public class MyObject {
    private static MyObject myObject;

    private MyObject() {
    }

    public static MyObject getInstance() {

        if (null == myObject) {
            // do somethings
            synchronized (MyObject.this) {
                myObject = new MyObject();
            }
        }

        return myObject;
    }
}

但是这种却不是线程安全的,在多线程下,依然会有可能产生多个实例。

2.4 使用 DCL 双检查锁机制

public class MyObject {
    private volatile static MyObject myObject;

    private MyObject() {
    }

    public static MyObject getInstance() {

        if (null == myObject) {
            // do somethings
            synchronized (MyObject.this) {
                if (null == myObject) {
                    myObject = new MyObject();
                }
            }
        }

        return myObject;
    }
}
  1. 使用静态内部类实现单例模式
public class MyObject {

    // 内置类方式
    private static class MyObjectHandler {
        private static MyObject myObject = new MyObject();
    }

    private MyObject() {

    }

    public static MyObject getInstance () {
        return MyObjectHandler.myObject;
    }
}

// 摘录: 静态内部类是可以达到线程安全问题,但如果遇到序列化对象时,使用默认的方式运行得到的结果还是多例的。
// 如果碰到了序列化 IO 流对象,都是多例的,这是正常的。
4. 序列化与反序列化的单例模式的实现

public class MyObject implements Serializable {

    private static final long serialVersionUID = 888L;

    // 内置类方式
    private static class MyObjectHandler {
        private static MyObject myObject = new MyObject();
    }

    private MyObject() {

    }

    public static MyObject getInstance () {
        return MyObjectHandler.myObject;
    }

    // TODO: 关于这个方法网上是怎么说的
    protected Object readResolve() throws ObjectStreamException {
        System.out.println("go into readResolve");
        return MyObjectHandler.myObject;
    }
}


public class staticNestSingleton {
    public static void main(String[] args) {
        try {
            MyObject myObject = MyObject.getInstance();
            FileOutputStream fosRef = new FileOutputStream(new File("myObjectFile.txt"));

            ObjectOutputStream oosRef = new ObjectOutputStream(fosRef);
            oosRef.writeObject(myObject);
            oosRef.close();
            fosRef.close();
            System.out.println(myObject.hashCode());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            FileInputStream fisRef = new FileInputStream(new File("myObjectFile.txt"));
            ObjectInputStream iosRef = new ObjectInputStream(fisRef);
            MyObject newObject = (MyObject) iosRef.readObject();
            iosRef.close();
            fisRef.close();
            System.out.println(newObject.hashCode());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
  1. 使用 static 代码块实现单例
public class MyObject {

    private static MyObject myObject = null;

    private MyObject() {
    }

    static {
        myObject = new MyObject();
    }

    public static MyObject getInstance () {
        return myObject;
    }
}
  1. 使用 enum 枚举数据类型实现单例模式
  2. 完善使用 enum 枚举实现单例模式

相关文章推荐

设计模式学习笔记---单例模式(Java版)

GOF23(Group of  four) 创建型模式 单例模式,工厂模式,抽象工厂模式,建造者模式,原型模式。 结构型模式 适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式...

Java学习笔记(十三):为什么要使用单例模式

1、为啥使用单例模式: 单例模式也是一种比较常见的设计模式,它到底能带给我们什么好处呢?其实无非是三个方面的作用: 第一、控制资源的使用,通过线程同步来控制资源的并发访问; 第二、控制实例产生的数量...

Java学习笔记之单例模式

什么是单例模式? Java中单例模式定义;“一个类有且仅有一个实例,并且自行实例化向整个系统提供该实例。” 简单的说,这个类在系统中只存在唯一的一个对象,不像我们平时所创建的类,只要你new多少...

黑马程序员--Java学习笔记之面向对象思想(单例模式详解、匿名对象、静态、final)

一、数据类型:  1、基本数据类型:8种,boolean  char(16bit)  byte(8)  short(16)  int(32)  long(64)  float(32)  double(...

《Java多线程编程核心技术》学习笔记(三)——Lock、Timer、单例模式

Lock的使用使用ReentrantLock类在Java多线程中,可以使用synchronized关键字来实现线程之间同步互斥,但在JDK1.5中新增加了ReentrantLock类也能达到同样的效果...

Java学习笔记———《单例模式的7种实现详解》

最近学习了一下单例模式,整理如下,如有错误和不足之处欢迎各位批评纠正,互相学习! 第一种:懒汉式,线程不安全 package singleton; /** * Created by MJ ...

java单例模式学习笔记

单例模式 1、单例模式:保证一个类只有一个实例,并提供一个访问它的全局方法。 基本使用: public class SingleInstance { private static Sing...

Java学习笔记(注释、对象初始化过程、单例模式)

面向对象9.帮助文档的制作9.1注释- 原则: 1、注释形式统一 在整个应用程序中,使用具有一致的标点和结构的样式来构造注释。如果在其它项目中发现它们的注释规范与这份文档不同,按照这份规...

学习笔记——JAVA设计模式<1>单例模式

Group of four GFO23种设计模式 创建型模式建对象 单例模式 工厂模式 抽象工厂模式 建造者模式原型模式 结构性模式 适配器模式 桥接模式 装饰模式 组合模式...

java设计模式学习笔记1 单例模式

单例模式:指的是类 只能由自己生成唯一一个对象实例,并向其他对象提供这一实例。 实现单例模式有三种方法;常用的是所谓懒汉模式,与饿汉模式 1饿汉式:即在类在初始化的时候就已经自行实例化: publ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:单例模式的学习笔记(Java版)
举报原因:
原因补充:

(最多只允许输入30个字)