单利模式
单例模式有一下几类:
1、懒汉模式:
在使用的地方创建对象,起到延时加载的作用,但是容易产生线程安全的问题。
2、饿汉模式
在类创建的同时已经创建了一个静态变量供使用(一开始就亟不可待的创建了对象,饿汉比较形象的表面了这一点),因此不存在线程安全的问题。
懒汉模式:
懒汉模式又有几个分类
线程不安全的懒汉模式:
public class Single{ private static Single single = null ; private Sngle(){} public static Single getSingle(){ if(single == null){ single = new Single(); } return single ; } }
为什么说这是线程不安全的懒汉模式呢?
假设这样的场景:两个线程并发调用初始对象的方法如:getSingle();假设线程一先判断完single是否为null,既代码中的line A进入到line B的位置。刚刚判断完毕后,(并没有对single进行实例化)JVM将CPU资源切换给线程二,由于线程一还没执行line B,所以single仍然是空的,因此线程二执行了new Single()操作。片刻之后,线程一被重新唤醒,它执行的仍然是new Single()操作,好了,问题来了,这样内存就存在连个Single对象,因此单例模式就失去了意义。
为此,我们做了一点改进,解决线程不安全的问题
线程安全懒汉单例模式一:
public class Single{
private static Single single = null ;
private Sngle(){}
public static synchronized Single getSingle(){
//添加了同步锁 synchronized
if(single == null){
single = new Single();
}
return single ;
}
}
比起第一段代码仅仅在方法中多了一个synchronized修饰符,现在可以保证不会出线程问题了。但是这里有个很大(至少耗时比例上很大)的性能问题。除了第一次调用时是执行了Single的构造函数之外,以后的每一次调用都是直接返回single对象。返回对象这个操作耗时是很小的,绝大部分的耗时都用在synchronized修饰符的同步准备上,因此从性能上说很不划算。
懒汉模式三 线程安全
public class Single{
private static Single single = null ;
private Sngle(){}
public static Single getSingle(){
//添加了同步锁 synchronized
synchronized (Single.class){
if(single == null){
single = new Single();
}
return single ;
}
}
}
这样将synchronized移到代码内部,每次执行getSngle()方法的时候,还是会进行同步synchronized,所以又有另一个方法:
懒汉模式四 线程安全之双重锁定检查
public class Single{
private static Single single = null ;
private Sngle(){}
public static Single getSingle(){
//添加了同步锁 synchronized
if(single == null){
synchronized (Single.class){
if(single == null){
single = new Single();
}
return single ;
}
}
}
}
这样一来,只有在第一次初始化single对象的时候,才会进行同步锁,其他时候不在进行判断
饿汉模式
public class Single{
private static Single single = new Single();
private Sngle(){}
public static Single getSingle(){
if(single == null){
single = new Single();
}
return single ;
}
}
因为饿汉模式在类加载的时候就已经初始化了单例对象,所以不存在线程安全的问题,有利就有弊,如果该对象消耗资源比较多,希望延时加载时饿汉模式可能就无法做到。还有一种情况就是,如果单例对象在实例化时需要通过外部传参,那么饿汉模式也无法完成这一要求。
饿汉模式二
public class Single{
private static Single single = null;
static{
single = new Single();
}
private Sngle(){}
public static Single getSingle(){
if(single == null){
single = new Single();
}
return single ;
}
}
与上一种方式差不多,也是在类加载的时候进行实例化。
静态内部类方式实现单例模式
public class Single{
private static class InnerClass{
public static final Single SINGLE = new Single();
}
public static Single getSingle(){
return InnerClass.SINGLE ;
}
}
枚举实现单例
public enum Single{
SINGLE;
public void method(){}
}