单例模式【创建型模式】
1、这篇文章使用了一个工具格式化的,排版虽然看起来不是很好,但是真的比我自己排版要好。
2、没想到这篇文章发表在CSDN上竟然上了推荐。
3、单例模式面试经常被问到,今天看视频总结了下面的内容,大家可以好好看看,然后用自己的话总结下面试怎么说。
4、后面会一直学习完23种设计模式,都会分享出来。
所谓单例模式,就是对某个类只能存在一个对象实例,并且该类只提供一个获取其对象实例的方法(静态方法)
单例模式一共有八种方式
1、饿汉式 (静态常量)
2、饿汉式 (静态代码块)
3、懒汉式 (静态方法内部判断,线程不安全)
4、懒汉式 (线程安全,同步方法)
5、懒汉式 (线程不安全,同步代码块)
6、双重检查
7、静态内部类
8、枚举
1、饿汉式
1-1:饿汉式(静态常量)
1、构建
1、构造器私有化(防止 new) 2、类的内部创建对象 3、向外暴露一个静态的公共方法(getInstance)
2、代码演示
public class Main {
// 测试
public static void main(String[] args) {
Singleton one = Singleton.getInstance();
Singleton two = Singleton.getInstance();
System.out.println(one == two); // true
System.out.println("one.hashCode() = " + one.hashCode()); // 两个hashcode相同
System.out.println("two.hashCode() = " + two.hashCode());
}
}
class Singleton {
// 1、私有化,防止 new
private Singleton(){}
// 2、本类内部创建实例
private final static Singleton instance = new Singleton();
// 3、提供一个公有的静态方法,返回实例对象
public static Singleton getInstance(){
return instance;
}
}
3、分析
3-1:优缺点
•优点:写法比较简单,就是在类加载的时候完成实例化。避免了线程同步问题。•缺点:在类加载的时候就完成实例化,没有达到懒加载的效果。如果从始至终从未使用过这个实例,则会造成内存浪费。
1-2:饿汉式(静态代码块)
1、代码演示 (测试和上面的测试一样,就不赘述了)
class Singleton {
// 1、私有化,防止 new
private Singleton(){}
// 2、创建变量
private static Singleton instance;
// 3、静态创建对象
static {
instance = new Singleton();
}
// 4、提供一个公有的静态方法,返回实例对象
public static Singleton getInstance(){
return instance;
}
}
2、优缺点,和上面一样不再赘述。
2、懒汉式
1、懒汉式(线程不安全的)
1、代码演示
class Singleton {
// 1、私有化,防止 new
private Singleton(){}
// 2、创建变量
private static Singleton instance;
// 3、提供一个公有的静态方法,返回实例对象
public static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
2、优缺点
•优点:起到了懒加载的作用•缺点:线程不安全。(一个线程进入 if 语句后,还没来得及往下执行,另一个线程也通过了判断语句,这时候就会产生多个实例 )
2、懒汉式(使用 synchronized 同步方法, 保证线程安全)
1、代码演示
class Singleton {
// 1、私有化,防止 new
private Singleton(){}
// 2、创建变量
private static Singleton instance;
// 3、提供一个同步静态方法,返回实例对象。解决线程安全问题
public synchronized static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
2、优缺点
•优点:解决了线程安全的问题。•缺点:方法使用了同步,效率太低了。
3、懒汉式 (线程不安全,同步代码块)
不可以这样写,它连最起码的线程安全都无法保证。
1、代码演示
class Singleton {
private Singleton(){}
private static Singleton instance;
public static Singleton getInstance(){
if (instance == null){
synchronized(Singleton.class){
instance = new Singleton();
}
}
return instance;
}
}
3、双重检查
1、代码演示
class Singleton {
private Singleton(){}
private volatile static Singleton instance;
public static Singleton getInstance(){
if (instance == null){
// 1
synchronized(Singleton.class){
// 2
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
说明:volatile可以保证可见性、有序性,还有禁止指令重排序。比如当我们线程A已经执行到了 2,线程B执行到了 1。这个时候线程A执行结束创建了对象,B再进来了发现对象已经创建了(volatile的作用)就不再创建了。而之后的线程直接在第一个if就被挡住了。
2、优缺点
•优点:做到了懒加载、解决了线程安全问题和效率问题。
7、静态内部类
1、代码演示
class Singleton {
private Singleton(){}
private static class SingletonInstance{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return SingletonInstance.INSTANCE;
}
}
说明:
•外部类装载的时候,内部类不会进行装载的。•当我们调用getInstance的时候内部类会进行装载,装载的过程是线程安全的。
2、优缺点
•优点:避免线程安全问题,满足了延迟加载,效率高。
8、枚举
public class Main {
public static void main(String[] args) {
Singleton one = Singleton.INSTANCE;
Singleton two = Singleton.INSTANCE;
System.out.println(one == two);
System.out.println(one.hashCode());
System.out.println(two.hashCode());
}
}
enum Singleton {
INSTANCE;
public void fun(){
System.out.println("fun...");
}
}
2、优缺点
•优点:避免线程安全问题,而且还能防止反序列化重新创建新的对象。
9、其它
1、JDK里面哪使用到了单例模式?
Runtime里面就用到了单例模式的饿汉模式,它把构造方法私有化了,然后直接使用静态常量创建对象。
2、单例模式注意事项
•单例保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统的性能。•当想实例化一个单例类的时候,必须记住使用相应的获取对象的方法,而不是使用new•单例模式使用场景:需要频繁的进行创建和销毁的对象、创建对象时消耗过多或消费资源过多(重量级对象),但又经常使用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工程等)