博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式-单例模式
阅读量:4059 次
发布时间:2019-05-25

本文共 6559 字,大约阅读时间需要 21 分钟。

Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”

1.饿汉式

package testSingletonUnderMultiThreads;/** * @author zhangdi * 饿汉式 : 存在效率和资源占用问题 */public class Singleton_1_MyObject {
// 饿汉式private static Singleton_1_MyObject myObject = new Singleton_1_MyObject();// private 只有内部才能调用构造器private Singleton_1_MyObject() { super();}//private static Singleton_1_MyObject getInstance() { return myObject;}}

2.懒汉式:存在多线程下的线程安全问题

package testSingletonUnderMultiThreads;/** * @author zhangdi * 懒汉式:存在多线程下的线程安全问题 */public class Singleton_2_MyObject {
// 定义一个静态变量来记录类的唯一实例,但不初始化 private static Singleton_2_MyObject myObject; // 保证只有内部可以调用构造器 private Singleton_2_MyObject() { } public static Singleton_2_MyObject getInstance() { if (null != myObject) { } else { myObject = new Singleton_2_MyObject(); } return myObject; }}

3.懒汉式加锁 :可解决多线程下的同步问题,但是存在严重效率问题

/** * @author zhangdi *  synchronized 加锁 : 可解决多线程下的同步问题,但是存在严重效率问题 */public class Singleton_3_MyObject {
// 定义一个静态变量来记录类的唯一实例,但不初始化 private static Singleton_3_MyObject myObject; // 保证只有内部可以调用构造器 private Singleton_3_MyObject() { } //synchronized保证多线程下的懒汉式是线程安全的,但是问题在于,只有第一次执行时才需要同步,设置好MyObject后都不要同步这个方法了. synchronized public static Singleton_3_MyObject getInstance() { if (null != myObject) { } else { myObject = new Singleton_3_MyObject(); } return myObject; }}

4.DCL :双重加锁检查 :

volatile是必须的.

package testSingletonUnderMultiThreads;/** * @author zhangdi * 双重加锁检查  */public class Singleton_4_MyObject {
//ps:volatile 保证线程间共享变量的可见性,但不能保证原子性 //volatile确保myObject被初始化为singleton单例后,多个线程可以正确处理myObject private volatile static Singleton_4_MyObject myObject; private Singleton_4_MyObject() { } private static Singleton_4_MyObject getInstance() { //只有第一次才会彻底执行下面的代码 if (myObject == null) { synchronized (Singleton_4_MyObject.class) { //进入区块后,再检查一下,myObject仍为null,才创建实例 if(myObject == null){ myObject = new Singleton_4_MyObject(); } } } return myObject; }}

5 . 使用静态内部类 :静态内部类虽然保证了单例在多线程并发下的线程安全性,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的。

ps:静态内部类的加载不需要依附外部类,在使用时才加载,而不是在外部类加载时被加载

package testSingletonUnderMultiThreads;/** * @author zhangdi * 使用静态内部类  * 静态内部类虽然保证了单例在多线程并发下的线程安全性,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的。 */public class Singleton_5_MyObject {
//静态内部类的加载不需要依附外部类,在使用时才加载,而不是在外部类加载时被加载 private static class MyObjectHandler {
private static Singleton_5_MyObject myObject = new Singleton_5_MyObject(); } //私有构造器是必须的 private Singleton_5_MyObject() { } public static Singleton_5_MyObject getInstance() { return MyObjectHandler.myObject; }}

6.序列化与反序列化的单例模式实现

package testSingletonUnderMultiThreads;import java.io.ObjectStreamException;import java.io.Serializable;/** * @author zhangdi * 序列化与反序列化的单例模式实现 */public class Singleton_6_MyObject implements Serializable {
private static final long serialVersionUID = 1L; private static class MyObjectHandler {
private static Singleton_6_MyObject myObject = new Singleton_6_MyObject(); } private Singleton_6_MyObject() { } public static Singleton_6_MyObject getInstance() { return MyObjectHandler.myObject; } // 该方法在反序列化时会被调用,该方法不是接口定义的方法,有点儿约定俗成的感觉 protected Object readResolve() throws ObjectStreamException { System.out.println("调用了readResolve方法!"); return MyObjectHandler.myObject; }}

序列化与反序列化测试代码 :

package testSingletonUnderMultiThreads;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;/** * @author zhangdi * 序列化与反序列化测试代码 */public class SaveAndReadForSingleton {
public static void main(String[] args) { Singleton_6_MyObject singleton = Singleton_6_MyObject.getInstance(); File file = new File("MySingleton.txt"); try { FileOutputStream fos = new FileOutputStream(file); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(singleton); fos.close(); oos.close(); System.out.println(singleton.hashCode()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { FileInputStream fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); Singleton_6_MyObject rSingleton = (Singleton_6_MyObject) ois.readObject(); fis.close(); ois.close(); System.out.println(rSingleton.hashCode()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }}

7.static代码块实现单例

package testSingletonUnderMultiThreads;/** * @author zhangdi * 使用static代码块实现单例,也可以保证线程安全性,也有资源占用问题 */public class Singleton_7_MyObject {
private static Singleton_7_MyObject MyObject = null; private Singleton_7_MyObject(){} static { MyObject = new Singleton_7_MyObject(); } public static Singleton_7_MyObject getInstance() { return MyObject; }}

8.枚举实现单例模式

package testSingletonUnderMultiThreads;/** * @author zhangdi * 使用枚举  缺点 : 但是这样写枚举类的实现细节被完全暴露了,违反了“职责单一原则”? */public enum Singleton_8_MyObject_enum1 {    singletonFactory;    private MySingleton instance;    private Singleton_8_MyObject_enum1(){
//枚举类的构造方法在类加载是被实例化 instance = new MySingleton(); } public MySingleton getInstance(){ return instance; }}class MySingleton{
//需要获实现单例的类,比如数据库连接Connection public MySingleton(){} }

9.完善的枚举类实现单例模式

package testSingletonUnderMultiThreads;/** * @author zhangdi * 完善使用enum枚举实现单例模式:不暴露枚举类的实现细节   */public class Singleton_9_MyObject_enum2 {
//不暴露枚举类的实现细节 private enum MyEnumSingleton { singletonFactory; private MySingleton2 instance; private MyEnumSingleton() {
// 枚举类的构造方法在类加载时被实例化 instance = new MySingleton2(); } public MySingleton2 getInstance() { return instance; } } public static MySingleton2 getInstance() { return MyEnumSingleton.singletonFactory.getInstance(); }}class MySingleton2 {
// 需要获实现单例的类,比如数据库连接Connection public MySingleton2() { }}

转载地址:http://jawji.baihongyu.com/

你可能感兴趣的文章
C++报错:读取位置 0xFFFFFFFFFFFFFFFF 时发生访问冲突
查看>>
【数据结构周周练】005顺序队列与链队 -扑克牌的筛选
查看>>
【数据结构周周练】006队列基本操作-顺序结构及链式结构实现
查看>>
C++类、结构体、函数、变量等命名规则详解
查看>>
【数据结构周周练】007顺序结构实现完全二叉树操作- 求编号i与j最近公共祖先结点
查看>>
C++ goto语句详解
查看>>
【数据结构周周练】008 二叉树的链式创建及测试
查看>>
【数据结构周周练】009 二叉树的先序、中序、后序遍历(递归算法实现)
查看>>
【数据结构必备基本知识】递归与迭代的联系、区别与优缺点对比详解
查看>>
【数据结构周周练】010 递归算法实现二叉树的创建与遍历
查看>>
【数据结构周周练】011 非递归算法实现二叉树的遍历
查看>>
【数据结构周周练】012 利用队列和非递归算法实现二叉树的层次遍历
查看>>
【数据结构周周练】013 利用栈和非递归算法求二叉树的高
查看>>
【数据结构周周练】014 利用栈和非递归算法求链式存储的二叉树是否为完全二叉树
查看>>
【数据结构周周练】015 利用递归算法创建链式存储的二叉树并转换左右孩子结点
查看>>
【数据结构周周练】016 利用递归算法及孩子兄弟表示法创建树、遍历树并求树的深度
查看>>
【数据结构周周练】017 利用递归算法及孩子兄弟表示法创建森林、遍历森林并求森林的叶子结点个数
查看>>
【数据结构必备基本知识】数据结构常用预定义常量、类型及头文件
查看>>
【数据结构周周练】018 利用递归算法及中序遍历将二叉树线索化并遍历
查看>>
【数据结构周周练】019 利用递归算法创建二叉排序树并遍历
查看>>