单例设计模式:
保证一个类仅有一个实例,即该类的实例对象在内存中只有一个地址,并提供一个访问它的全局访问点。
一般用于工具类,实现步骤可概括为以下三步:
1、构造方法私有化
2、声明一个本类对象
3、给外部提供一个静态方法获取对象实例
有两种实现方式:
1、饿汉式(占用内存时间长,效率高,不建议采用)
2、懒汉式(占用内存时间短,效率低,建议采用)
文章最后还会提供懒汉式单例设计模式的优化方案、静态内部类的优化方案、枚举的单例方案。
1、饿汉式(占用内存时间长,效率高,不建议采用)
class Singleton1{
private Singleton1(){};//构造方法私有化
private static Singleton1 ss = new Singleton1();//声明一个本类对象,马上实例化
//主函数当中使用此类的getInstance()函数,即可得到系统当前已经实例化的该类对象,
//若当前系统还没有实例化过这个类的对象,则调用此类的构造函数
public static Singleton1 getInstance(){ //给外部提供一个静态方法
return ss;
}
}
//main方法中直接调用类的getInstance()方法即可
Singleton1 s1 = Singleton1.getInstance();
2、懒汉式(占用内存时间短,效率低,建议采用)
class Singleton2{
private Singleton2(){}
private static Singleton2 ss;//声明一个对象,不马上实例化
public static Singleton2 getInstance(){
if(null == ss){ //如果该对象还没有被实例化过,再进行实例化
ss = new Singleton2();
}
return ss;
}
}
//main方法中直接调用类的getInstance()方法即可
Singleton1 s1 = Singleton1.getInstance();
3、单例设计模式优化
(1)解决多线程安全问题;
(2)加上volatile关键字保证变量一致性;
(3)防止反射调用私有方法;
(4)让单例可以被序列化
class Singleton implements Serializable{ //实现第(4)点
private volatile static Singleton ss = null;//实现第(2)点
private Singleton(){
//实现第(3)点
if(null != ss){
throw new RuntimeException("此类对象为单例模式,已经被实例化");
}
}
public static Singleton getInstance(){ //同步代码块与双重判断实现第(1)点
if(null == ss){
synchronized (Singleton.class){
if(null == ss){
ss = new Singleton();
}
}
}
return ss;
}
}
//main方法中直接调用类的getInstance()方法即可
Singleton ss = Singleton.getInstance();
4、静态内部类单例
*单例采用静态内部类的方式,是最完美的
JVM保证单例
加载外部类时不会加载内部类,这样就可以实现懒加载,且没有现成安全问题
public class SingletonPattern {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
//只有一句话,lamba的{}可以省略
new Thread(() ->
System.out.println(Singleton.getInstance().hashCode())
).start();
}
}
}
class Singleton{
private Singleton(){}
private static class SingletonInner{
private final static Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return SingletonInner.INSTANCE;
}
}
5、枚举类实现单例
Java创始人推荐的方式
用枚举的方式,不仅可以解决线程同步问题。
还可以防止反序列化,因为枚举类没有构造方法,反射无法通过.class文件new对象
public enum SingletonEnum {
INSTANCE;
public void m(){}
public static void main(String[] args){
for (int i = 0; i < 100; i++) {
//只有一句话,lamba的{}可以省略
new Thread(() ->
System.out.println(SingletonEnum.INSTANCE.hashCode())
).start();
}
}
}