1、单例模式的定义
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例
2、单例模式的特点
1、单例类只有一个实例
2、单例类必须自己穿件自己的唯一实例
3、单例类必须给其他类提供这个实例
单例模式保证了全局对象的唯一性,比如系统启动读取配置文件就需要单例保证配置的唯一性
前面说的是单例模式的一些基础,很简单。主要是分析一下单例模式的线程安全问题
1、饿汉式单例模式(立即加载的方式)
public class Singletonl{
private Singletonl(){};//此处的私有化是避免了类在外部被实例化
private Singletonl single = new Singletonl();
public static Singletonl getInstance(){
return single;
}
}
饿汉式单例在类加载初始化的时候就创建好了一个静态对外的实例供给外部使用,除非系统重启,那么这个对象是不会改变的。所以本身线程是安全的
但是我们知道java的反射机制能够实例化构造方法是private的类,那基本上都会使得使用java单例实例失效。所以我们姑且认为反射机制是不存在的
2、懒汉式单例(延迟加载方式)
public class Singleton2{
private Singleton2(){};
private static Singleton2 single = null;
public static Singgleton2 getInstance(){
if(single==null){
single = new Singleton2();
}
return single;
}
该示例虽然用了延迟加载的方式实现了懒汉式单例,但是在多线程的环境下会产生多个Single对象
下面我们来改造一下
- 使用synchronized同步锁
public class Singleton3{
private Singleton3(){};
private static Singleton3 single = null;
public static Singgleton2 getInstance(){
// 等同于 synchronized public static Singleton3 getInstance()
synchronized(Singleton3.class){
// 注意:里面的判断是一定要加的,否则出现线程安全问题
if(single==null){
single = new Singleton3();
}
}
return single;
}
在这个方法上加了synchronized同步锁或使用同步代码块对类同步锁,此方法虽然解决了多个实例对象问题,但是运行效率却很低。下个线程想获取对象,就必须等上一个线程释放锁之后才能进行
public class Singleton4 {
// 私有构造
private Singleton4() {}
private static Singleton4 single = null;
// 双重检查
public static Singleton4 getInstance() {
if (single == null) {
synchronized (Singleton4.class) {
if (single == null) {
single = new Singleton4();
}
}
}
return single;
}
}
此方法进行了双重检测,避免了整个方法被加锁,提高了执行的效率。
3、静态内部类实现
public class Singleton6{
private Singgleton6(){};
private static class InnerObject{
private static Singleton6 single= new Singleton6();
}
public static Singleton6 getInstance(){
return InnerObject.single;
}
}
静态内部类虽然保证了单例在多线程并罚下的线程安全,但是在遇到序列化对象的时候,默认的方式运行得到的结果就是多例的。
4、.内部枚举类实现
public class SingletonFactory {
// 内部枚举类
private enum EnmuSingleton{
Singleton;
private Singleton8 singleton;
//枚举类的构造方法在类加载是被实例化
private EnmuSingleton(){
singleton = new Singleton8();
}
public Singleton8 getInstance(){
return singleton;
}
}
public static Singleton8 getInstance() {
return EnmuSingleton.Singleton.getInstance();
}
}
class Singleton8{
public Singleton8(){}
}