本文共 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/