设计模式-单例模式
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() {
}
}