单例
零、单例设计模式
单例设计模式:采取一定的方法保证整个软件系统中,对某个类只能存在一个对象实例;并且该类只提供一个取得其对象实例的静态方法。
1、构造器私有化(防止new)
2、向外暴露一个静态的公共方法
一、饿汉式:成员变量初始化
1、代码
/** * @Author: dashu * @Description: 单例(饿汉式:成员变量初始化) * @Version: 1.0 */
public class Singleton {
private final static Singleton singleton = new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return singleton;
}
}
2、小结
优点:写法简单,在类装载时就完成实例化。避免了线程同步问题,线程安全的。
缺点:没有达到懒加载的效果,如果从始至终从未使用该实例,则造成内存的浪费
结论:该单例模式可以用,但可能造成内存浪费
二、饿汉式:静态代码块初始化
1、代码
/** * @Author: dashu * @Description: 单例(饿汉式:静态代码块初始化) * @Version: 1.0 */
public class Singleton {
private final static Singleton singleton;
static {
singleton = new Singleton();
}
private Singleton(){
}
public static Singleton getInstance(){
return singleton;
}
}
2、小结
优点:写法简单,在类装载时就完成实例化。避免了线程同步问题,线程安全的。
缺点:没有达到懒加载的效果,如果从始至终从未使用该实例,则造成内存的浪费
结论:该单例模式可以用,但可能造成内存浪费
三、懒汉式,线程不安全
1、代码
/** * @Author: dashu * @Description: 单例(懒汉模式) * @Version: 1.0 */
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
2、小结
优点:起到了懒加载的效果
缺点:只能在单线程下使用。如果在多线程下,一个线程进入了if (singleton == null)
语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时会产生多个实例,违反单例模式。
结论:不要使用这种方式
四、懒汉模式:同步方法,线程安全
1、代码
/**
* @Author: dashu
* @Description: 单例(懒汉模式:同步方法)
* @Version: 1.0
*/
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static synchronized Singleton getInstance(){
if (singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
2、小结
优点:起到了懒加载的效果,同时解决了线程安全问题
缺点:效率低下,在多线程下,每个线程在获取该类的实例时,执行到getInstance()
方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return
就行了。
结论:不推荐使用
五、懒汉模式:同步代码块,线程不安全
1、代码
/** * @Author: dashu * @Description: 单例(懒汉模式:同步代码块) * @Version: 1.0 */
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
singleton = new Singleton();
}
}
return singleton;
}
}
2、小结
优点:起到了懒加载的效果
缺点:线程不安全的,在多线程下,一个线程进入了if (singleton == null)
语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时会产生多个实例,违反单例模式。
结论:不要使用这种方式
六、懒汉模式:同步代码块,双重验证
1、代码
/** * @Author: dashu * @Description: 单例(懒汉模式:同步代码块,双重验证) * @Version: 1.0 */
public class Singleton {
private static Singleton singleton;
private Singleton(){
}
public static Singleton getInstance(){
if (singleton == null){
synchronized (Singleton.class){
if (singleton == null){
singleton =new Singleton();
}
}
}
return singleton;
}
}
2、小结
优点:线程安全,懒加载,效率高
结论:推荐使用
七、静态内部类
1、代码
public class Singleton {
public static class SingletonInstance {
private final static Singleton INSTANCE = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
2、小结
这种方式采用了类装载的机制来保证初始化实例时只有一个线程。
静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance()
方法,才会装载SingletonInstance
类,从而完成Sinleton的实例化。
类的静态属性只会在第一次加载类的时候初始化,这里JVM帮助我们保证了线程的安全性,在类初始化时,别的线程是无法进入的
优点:线程安全,懒加载,效率高
结论:推荐使用
八、枚举
1、代码
/** * @Author: dashu * @Description: 单例(枚举) * @Version: 1.0 */
public enum Singleton {
INSTANCE;
}
2、小结
借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能放hi反序列化重新创建新的对象
这种方式是Effective Java
作者Josh Bloch
提倡的方式
结论:推荐使用
九、测试
1、前七种
/** * @Author: dashu * @Description: 测试 * @Version: 1.0 */
public class Main {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
System.out.println("singleton1 == singleton2 :" + (singleton1 == singleton2));
System.out.println("singleton1.hashCode() :" + singleton1.hashCode());
System.out.println("singleton2.hashCode() :" + singleton2.hashCode());
}
}
2、枚举
/** * @Author: dashu * @Description: 测试 * @Version: 1.0 */
public class Main {
public static void main(String[] args) {
Singleton singleton1 = Singleton.INSTANCE;
Singleton singleton2 = Singleton.INSTANCE;
System.out.println("singleton1 == singleton2 :" + (singleton1 == singleton2));
System.out.println("singleton1.hashCode() :" + singleton1.hashCode());
System.out.println("singleton2.hashCode() :" + singleton2.hashCode());
}
}
十、单例模式注意事项和细节说明
单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new
单例模式的使用场景:
1、需要频繁创建销毁的对象
2、创建对象时耗时过多或耗费资源过多(即:重量级对象)
3、经常用到的对象
4、工具类对象
5、频繁访问数据库或文件的对象(如:数据源、session工厂等)
十一、总结
类型 | 是否支持懒加载 | 线程是否安全 | 效率 | 推荐指数 |
---|---|---|---|---|
饿汉式:成员变量初始化 | 否 | 是 | 高 | 5 |
饿汉式:静态代码块初始化 | 否 | 是 | 高 | 5 |
懒汉式 | 是 | 否 | 高 | 0 |
懒汉模式:同步方法 | 是 | 是 | 底 | 5 |
懒汉模式:同步代码块 | 是 | 否 | 高 | 0 |
懒汉模式:同步代码块,双重验证 | 是 | 是 | 高 | 10 |
静态内部类 | 是 | 是 | 高 | 10 |
枚举 | 否 | 是 | 高 | 10 |
文章评论