单例模式与多线程(二)
来源:互联网 发布:php程序员的工作常态 编辑:程序博客网 时间:2024/05/28 06:04
在单例模式与多线程(一)中,介绍了四种在多线程环境下实现的单例模式:饿汉模式、懒汉模式、静态内部类实现方式和static代码块实现方式。下面介绍使用enum枚举数据类型实现单例和使用序列化与反序列化实现单例。
下面先介绍使用enum枚举数据类型实现单例:
枚举enum和静态代码块的特性相似,在使用枚举类时,构造方法会被自动调用,因此可以应用这个特性实现单例设计模式。
具体示例如下:
package com.javapatterns.singleton;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;/** * 使用enum枚举数据类型实现单例 */public class Test { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread t1 = new Thread(myRunnable); Thread t2 = new Thread(myRunnable); Thread t3 = new Thread(myRunnable); t1.start(); t2.start(); t3.start(); }} class MyObject { //将枚举类作为MyObject的内部类,这样可以避免因枚举类暴露而违反"职责单一原则" public enum MyEnumSingleton{ connectionFactory; //提供一个Connection类型的变量 private Connection connection; //构造方法私有化 private MyEnumSingleton() { try { System.out.println("创建MyObject对象"); String driverName = "com.mysql.jdbc.Driver"; String url = "jdbc:mysql://localhost:3306/mydb"; String name = "root"; String password = ""; Class.forName(driverName); connection = DriverManager.getConnection(url, name, password); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } //提供一个公有的获取Connection类型的方法 public Connection getConnection() { return connection; } } //提供一个公有的静态的获取Connection类型的方法,在该方法中通过枚举类中的变量connectionFactory调用公有的获取Connection类型的方法 public static Connection getConnection() { return MyEnumSingleton.connectionFactory.getConnection(); }}/* * 通过实现Runnable接口实现多线程 */class MyRunnable implements Runnable { @Override public void run() { System.out.println(MyObject.getConnection().hashCode()); }}
运行结果如图 4-1所示
图 4-1控制台打印的hasCode是同一个值,说明对象是同一个,也就说明使用enum枚举数据类型实现了单例。
接着介绍序列化与反序列化的单例模式实现:
静态内部类可以达到线程安全问题,但如果遇到序列化对象时,使用默认的方式运行得到的结果还是多例的。
下面进行演示:
package com.javapatterns.singleton;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;import java.io.Serializable;public class SaveAndRead { public static void main(String[] args) { try { MyObject mObject = MyObject.getInstance(); FileOutputStream fosRef = new FileOutputStream(new File("myObjectFile.txt")); ObjectOutputStream oosRef = new ObjectOutputStream(fosRef); oosRef.writeObject(mObject); oosRef.close(); fosRef.close(); System.out.println(mObject.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 mObject = (MyObject) iosRef.readObject(); iosRef.close(); fisRef.close(); System.out.println(mObject.hashCode()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }}class MyObject implements Serializable { private static final long serialVersionUID = 888L; private static class MyObjectHandler { private static final MyObject myObject = new MyObject(); } private MyObject() { } public static MyObject getInstance() { return MyObjectHandler.myObject; } // protected Object readResolve() // { // System.out.println("调用了readResolve方法!"); // return MyObjectHandler.myObject; // // }}
运行结果如图 4-2所示
图 4-2 不是同一个对象
解决办法就是在反序列化中使用readResolve()方法。
去掉如下代码的注释:
protected Object readResolve() { System.out.println("调用了readResolve方法!"); return MyObjectHandler.myObject; }
去掉后运行结果如图 4-3所示
图 4-3 是同一个对象
(正在学习高洪岩先生著的《java多线程编程核心技术》,例子摘自此书,有兴趣的可以查阅此书)
阅读全文
0 0
- 单例模式与多线程(二)
- 单例模式与多线程
- 单例模式与多线程
- 单例模式与多线程
- 单例模式与多线程
- 单例模式与多线程
- 单例模式与多线程
- 单例模式与多线程
- 单例模式与多线程
- 单例模式与多线程
- 单例模式与多线程
- 单例模式与多线程
- 多线程安全(二)之单例模式
- 探讨单例模式与多线程单例模式
- 单例模式与多线程的关系
- 【转】JAVA 单例模式与多线程
- JAVA 单例模式与多线程
- JAVA 单例模式与多线程
- IDEA main方法自动补全
- hls之m3u8、ts流格式详解
- Android中View创建的流程
- BZOJ3687 简单题 解题报告 【递推】【bitset】
- jpa Specification使用
- 单例模式与多线程(二)
- 全局变量重复定义
- Python机器学习笔记——概述
- unity中使用www加载本地资源
- 普元 EOS Platform 7.6 webservice图元添加自定义Header
- 块存储、文件存储、对象存储
- 高并发下生成订单唯一流水号的方法
- mysql数据库日期以字符串形式存储
- 类模板为什么不分文件