单例模式
顾名思义,就是表示单个实例(对象)的模式,一个类只能有一个对象
怎样实现单例模式
首先对象从何而来,对象是调用构造方法进行创建的,所有我们要控制构造方法
- 私有化构造方法
- 对外提供一个公共可访问的方法,返回该类对象
- 提前准备一个私有化的静态的对象,保证唯一,且只能本类访问
饿汉模式
饿汉模式:提前准备好对象
public class HungryMode
{
//提前准备好唯一对象,private避免外界直接访问,static保证独享唯一
private static HungryMode instance = new HungryMode();
//私有化构造方法
private HungryMode(){}
//提供公共可访问的方法,返回该类对象,static:无需对象,直接通过类名调用
public static HungryMode getInstance(){
return instance;
}
}
懒汉模式
懒汉模式:需要时,创建对象
public class LazyMode
{
//提前定义,但不创建对象,private避免外界直接访问,static保证独享唯一
private static LazyMode instance;
//私有化构造方法
private LazyMode(){}
//提供公共可访问的方法,返回该类对象,static:无需对象,直接通过类名调用
public static LazyMode getInstance(){
if(instance == null){
instance = new LazyMode();
}
return instance;
}
}
懒汉模式-线程安全问题
当多个线程同时访问时,懒汉模式可能会产生线程安全问题,我们可以通过同步锁机制来解决
public class LazyMode
{
private static LazyMode instance;
private LazyMode(){}
public static synchronized LazyMode getInstance(){
if(instance == null){
instance = new LazyMode();
}
return instance;
}
}
加入同步函数后线程安全问题解决了,但是每次获取对象都要判断锁,效率比较低
我们可以使用双重校验锁方式来解决效率问题
public class LazyMode
{
private static LazyMode instance;
private LazyMode(){}
public static LazyMode getInstance(){
/*如果第一个线程获取到了单例的实例对象,
* 后面的线程再获取实例的时候不需要进入同步代码块中了*/
if(instance == null){
//同步代码块用的锁是单例的字节码文件对象,且只能用这个锁
synchronized (LazyMode.class) {
if (instance == null) {
instance = new LazyMode();
}
}
}
return instance;
}
}