在多线程模式下,惰性初始化会使多个线程同时初始化该单体,造成一个JVM中多个单例类型的实例。如果单例类型的成员变量在运行过程中发生变化,会造成多个单例类型的实例不一致。
如何保证线程的安全性?
1、添加同步锁
public static synchronized Singleton getInstance();虽然引入了同步代码,但是不会影响系统性能(这段代码只在最开始的时候执行一次)
2. 同步代码块
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
singleton = new Singleton();
}
}
return singleton;
}
}
3、双重检查(线程安全的最优写法)
public static SingletonThreadSafe getInstance() {
if (instance == null) {
synchronized (SingletonThreadSafe.class) {
if (instance == null) {
instance = new SingletonThreadSafe();
}
}
}
return instance;
}
4、静态内部类
public class Singleton {
private Singleton() {}
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
5、读/写方式
设置计数器,每次读取信息前,计数器+1,读完后-1。使用notifyAll()解除在该对象调用wait()的阻塞状态。只有计数器为0时,才能更新数据,同时调用wait()阻塞所有读属性的调用。
6、影子实例
更新属性时,直接生成另一个单例对象实例,这个生成的单例对象实例将从数据库、文件或程序中读取最新的信息,然后将这些信息直接赋给旧单例对象的属性。
一般采用饿汉式,若对资源十分在意可以采用静态内部类,不建议采用懒汉式及双重检测。
如何区别单体类和工具类?
1、看状态。工具类无状态,单体类可能有(可变单体类)可能无(提供工具类性质的对象)
2、是否承担唯一的责任,提供唯一的实例。
单体模式和全是静态方法的工具类区别?
1、类被load的时候,静态工具类已经被初始化了。单体可以自己控制初始化过程。
2、单体可以继承或被别的类继承。静态工具类不能(继承有非静态方法的类后,无法保证只有一个实例)
3、单体可以扩展到双体、多体。静态工具类没有可扩展性。
单例模式的多例类(多例模式(有上限和无上限))
多例可以有多个实例。
多例类必须自己创建,管理自己的实例,并向外界提供自己的实例。
它允许有限个(扔骰子、线程池)或无线个实例(购物车),并向整个JVM提供自己实例的类叫多例类,这种叫多例模式。
多例代码
/**
* 多例模式
*/
public class Multipleton {
// 多例数量
private static final int N = 10;
// 存放N个实例对象的容器
private static ArrayList<Multipleton> list = new ArrayList<Multipleton>(N);
// 每个对象的序号 标识
private int no;
// 私有构造方法 防止外界应用程序实例化
private Multipleton(int no) {
this.no = no;
System.out.println("-- Create Multipleton Object[" + no + "]!");
}
// 实例化N个对象实例
static {
// 添加Multipleton对象实例
//有上限
for (int i = 0; i < N; i++) {
list.add(new Multipleton(i));
}
//无上限,去掉i的限制即可
}
/**
* 随机获得 实例对象
*/
public static Multipleton getRandomInstance() {
// 获得随机数字
int num = (int) (Math.random() * N);
// 获得list中的对象实例
return list.get(num);
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
------------------------------------------------------------------------------------------
//客户端
public class MultipletonClient {
public static void main(String[] args) {
// 获得Multipleton对象实例
Multipleton multipleton = Multipleton.getRandomInstance();
System.out.println("multipleton:" + multipleton.getNo());
// 在次获得Multipleton对象实例
Multipleton multipleton2 = Multipleton.getRandomInstance();
System.out.println("multipleton2:" + multipleton2.getNo());
// 比较两个对象是否是同一个对象实例
if (multipleton == multipleton2) {
System.out.println("--这是同一个对象!");
} else {
System.out.println("--这是不同的对象!");
}
}
}
测试结果: