单例模式
所谓的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例
,并且该类只提供一个取得其对象实例的方法(静态的)
饿汉式(静态常量)
- 构造器私有化(防止new)
- 类的内部创建对象
- 向外暴露一个静态的公共方法
class Singleton{
//1.构造器私有化
private Singleton(){}
//2.类内部创建对象实例
private final static Singleton singleton = new Singleton();
//3.提供一个公共的静态方法,返回实例对象
public static Singleton getSingleton(){
return singleton;
}
}
优点 :简单,因为在类装载时就完成了实例化。避免了线程同步的问题
缺点:在类装载的时候完成实例化,没有达到懒加载的效果。如果自始至终没有使用这个实例,则会造成浪费
饿汉式(静态代码块)
将实例的创建放到静态代码块中
class Singleton{
//1.构造器私有化
private Singleton(){}
//2.类内部创建对象实例
private final static Singleton singleton;
//2.1在静态代码块中创建对象
static{
singleton = new Singleton();
}
//3.提供一个公共的静态方法,返回实例对象
public static Singleton getSingleton(){
return singleton;
}
}
懒汉式(线程不安全)
class Singletion{
private Singletion(){}
private static Singletion singletion;
//提供一个静态共有方法,当使用该方法时,才去创建
public static Singletion getSingletion(){
if(singletion == null){
singletion = new Singletion();
}
return singletion;
}
}
优点:需要时才创建实例,节省资源
缺点:线程不安全,只能单线程中使用。当一个线程进入if判断语句时,还没来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例
懒汉式(线程安全,同步方法)
class Singletion{
private Singletion(){}
private static Singletion singletion;
//在方法上添加synchronized 来保证线程安全
public static synchronized Singletion getSingletion(){
if(singletion == null){
singletion = new Singletion();
}
return singletion;
}
}
优点:解决了线程安全问题
缺点:效率太低,每个线程在获取实例的时候,执行方法都要进行同步。而其实这个方法只执行一次实例化就足够了,后面的想获取实例之间return就行了
懒汉式(线程安全,同步代码块)
class Singletion{
private Singletion(){}
private static Singletion singletion;
//用同步代码块代替同步方法 但是无效
public static Singletion getSingletion(){
if(singletion == null){
synchronized(Singletion.class){
singletion = new Singletion();
}
}
return singletion;
}
}
这种方式本意是对同步方法方式的改进,因为同步方法效率太低,改为同步产生实例化的代码块
但是这种方式并不能起到线程同步的作用。跟线程不安全的方式遇到情况一样,假如一个线程进入了if,但还未创建实例,另一个线程也进入了if,则创建了多个实例
双重检查(DoubleCheck)
class Singletion{
private Singletion(){}
//用volatile进行修饰,让修改值立即更新到主存
private static volatile Singletion singletion;
//解决线程安全问题、效率和懒加载问题
public static Singletion getSingletion(){
if(singletion == null){
//创建实例后就不会在执行同步代码
synchronized(Singletion.class){
if(singletion == null){
singletion = new Singletion();
}
}
}
return singletion;
}
}
进行了两次if检查,这样可以保证线程安全
实例化代码只执行一次,后续在访问时,直接return实例,避免了同步代码
静态内部类
静态内部类特点:
- 外部类装载时,静态内部类不会立即装载(保证懒加载)
- 当调用静态内部内里的静态变量时,静态内部类会被装载。jvm类装载时线程是安全的(保证线程安全)
class Singletion{
//构造器私有
private Singletion(){}
//静态内部类,类中有一个静态属性
private static class SingletionInstance{
private static final Singletion singletion = new Singletion();
}
//之间返回内部类的静态属性
public static Singletion getSingletion(){
return SingletionInstance.singletion;
}
}
这种方式采用了类装载的机制来保证初始化实例只有一个线程
静态内部类方式在Singleton类被装载时并不会立刻实例化,二十在需要实例化时,调用实例化方法,才会装载内部类,完成实例化
类的静态属性只会在第一次加载类的时候初始化,所以在这里,jvm帮我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的
枚举
使用枚举可以实现单例
enum Singleton{
singletion;
}
不仅能够避免多线程的问题,而且还能防止反序列化重新创建新的对象