单例模式
简介
采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。
单例模式步骤
- 构造器私有化(防止new)
- 类的内部创建对象
- 向外暴露一个静态的公共方法
- 代码实现
1、饿汉式(静态常量)
public class Singleton {
public static void main(String[] args) {
// 测试是否单例
Singleton1 instance = Singleton1.getInstance();
Singleton1 instance2 = Singleton1.getInstance();
System.out.println(instance == instance2);
System.out.println("instance.hashCode()="+instance.hashCode());
System.out.println("instance2.hashCode()="+instance2.hashCode());
}
}
class Singleton1{
//1.私有化构造方法
private Singleton1(){}
//2.类的内部创建对象
private final static Singleton1 instance = new Singleton1();//static只加载一次,所有实例对象只有一次
//3.向外暴露一个静态的公共方法
public static Singleton1 getInstance(){
return instance;
}
}
2.饿汉式(静态代码块)
//main测试代码略
class Singleton1{
//1.私有化构造方法
private Singleton1(){}
private static Singleton1 instance;
//2.类的内部创建对象
static {
instance = new Singleton1();
}
//3.向外暴露一个静态的公共方法
public static Singleton1 getInstance(){
return instance;
}
}
3.懒汉式(线程不安全)
//main测试代码略
class Singleton1{
//1.私有化构造方法
private Singleton1(){}
private static Singleton1 instance;
//2.类的内部创建对象
//3.向外暴露一个静态的公共方法
public static Singleton1 getInstance(){
if (instance == null) {
instance = new Singleton1();
}
return instance;
}
}
线程不安全,不推荐使用,违背了单例模式的初衷。
4.懒汉式(线程安全)
//main测试代码略
class Singleton1{
//1.私有化构造方法
private Singleton1(){}
private static Singleton1 instance;
//2.类的内部创建对象
//3.向外暴露一个静态的公共方法
public static synchronized Singleton1 getInstance(){//synchronized线程同步
if (instance == null) {
instance = new Singleton1();
}
return instance;
}
}
加入了synchronized使线程同步,也降低了效率,当多个线程同时使用该方法时,就必须排队一个个来。不推荐使用。
5.双重检查(推荐使用)
//main测试代码略
class Singleton1{
//1.私有化构造方法
private Singleton1(){}
private static volatile Singleton1 instance;//volatile当该值变化时,所有线程都会跟着变化
//2.类的内部创建对象
//3.向外暴露一个静态的公共方法
public static Singleton1 getInstance(){
if (instance == null) {//不为null的就会直接返回,没有同步的约束提升了效率。
//假如有a,b两个线程都为null进入这里,使用同步,让a先进去创建了一个实例instance,b再进去时instance不为null则会被直接返回
synchronized (Singleton1.class) {
if (instance == null) {
instance = new Singleton1();
}
}
}
return instance;
}
}
6.静态内部类(推荐使用)
//main测试代码略
class Singleton1{
//1.私有化构造方法
private Singleton1(){}
//2.类的内部创建对象
private static class SingletonInstance{
private final static Singleton1 INSTANCE = new Singleton1();
//静态属性只会加载一次
}
//3.向外暴露一个静态的公共方法
public static Singleton1 getInstance(){
return SingletonInstance.INSTANCE;// 内部类只有被调用才加载
}
}
7.枚举类(推荐使用)
public class Singleton {
public static void main(String[] args) {
Singleton1 instance = Singleton1.INSTANCE;
Singleton1 instance2 = Singleton1.INSTANCE;
System.out.println(instance == instance2);
System.out.println("instance.hashCode()="+instance.hashCode());
System.out.println("instance2.hashCode()="+instance2.hashCode());
}
}
enum Singleton1{
INSTANCE;
}
饿汉式与懒汉式的区别
饿汉式是类加载时就加载,懒汉式是用到在加载,不会造成内存浪费。