Java 单例模式
摘要:博主在学习剑指offer过程中,结合另外一位道友总结Java的单例模式:https://www.cnblogs.com/cielosun/p/6582333.html
如有不足,希望大佬指点:
应用单例模式的场景:由于程序的设计,我们需要某个类同时且最多只需保留一个对象,此时我们就需要单例模式;
特点:
- 单例只能有一个实例;
- 单例类必须创建自己的唯一实例;
- 单例类必须向其他对象提供这一实例;
module1:不好的解法一:只适用于单线程环境(又称懒汉模式)
public class Singleton1 {
private Singleton1() {
}
private static Singleton1 singleton = null;
public static Singleton1 getInstance() {
if (singleton == null) {
singleton = new Singleton1();
}
return singleton;
}
}
缺陷:懒汉模式在多线程的情况下存在问题:设想两个线程同时运行至判断singleton是否为null,并且instance的确没有创建的时候,那么两个线程都会创建singleton实例,此时便不符合单例模式了;解决方案:加锁,使用sychronized;
module2:不好的解法二:线程安全的懒汉模式,但是效率不高;
public class Singleton1 { private Singleton1() { } private static Singleton1 singleton = null; public static synchronized Singleton1 getInstance() { if (singleton == null) { singleton = new Singleton1(); } return singleton; } }
缺陷:此时的效率不是很高,因为sychronized在保证单线程访问的情况下,却使得效率降低;1)加锁是一个非常耗时的操作 2)假设有两个线程同时想创建一个实例,由于同一时刻只有一个线程能够得到同步锁,当第一个线程上锁时,另外一个线程只能等待,且上锁线程占据其他资源,降低效率。更加尴尬的是第二个线程拿到“钥匙”时,实例已经被第一个线程创建出来了。
module3:可行的解法三:加同步锁两次判断实例是否存在(双重效验锁法)
public class Singleton1 { private Singleton1() { System.out.println("创建弯沉"); } private static Singleton1 singleton; public static Singleton1 getInstance() { if (singleton == null) { synchronized (Singleton1.class) { if (singleton == null) { singleton = new Singleton1(); } } } return singleton; } }
缺陷:module3加锁机制来保证最多只有一个实例,并且用两个if来实现提高效率;这样的代码实现起来比较复杂,容易出错;
我们可以使用java中的static 特性(确保只是使用一次)来实现单例模式;
module4:强烈推荐的解法一:利用静态构造函数(饿汉模式)
public class Singleton1 { private Singleton1() { } private static Singleton1 singleton = new Singleton1(); public static Singleton1 getInstance() { return singleton; } }
缺陷:代码虽然已经十分的简洁,但是没有达到Lazy loading的效果:静态函数的调用不是程序员掌控的,会过早地创建实例,从而降低内存的使用效率:
module5:强烈推荐的解法二:实现按需创建实例
public class Singleton1 { private Singleton1() { } private static class Nested { private static Singleton1 instance = new Singleton1(); } public static Singleton1 getInstance() { return Nested.instance; } }
看到这里,你已经无敌啦!去吧,骚年。如果有帮到你,请点赞哦!如果有不足,欢迎指出;