5. Singleton Pattern 单例模式—饿汉、懒汉与迭代后的懒汉

单例模式主要符合单一职能原则。当一个类的职责是一定的,而且整个程序中不需要生成第二个此类的对象,而且如果生成第二个此类的对象的话还会有问题(比如我之前写的联棋游戏,里面的棋盘就应该始终只有一个对象,如果有两个会造成混乱),为了防止生成两个对象,而且节约内存,会使用单例模式。使用单例模式的典型场景比如数据库连接类,游戏主流程控制类等。

解决思路:

1.不允许其他程序使用new创建该类对象。(别人new不可控)
2.在该类中创建一个本类实例。
3.对外提供一个方法让其他程序可以获取该对象。

解决步骤:

1.私有化该类的构造函数
2.通过new在本类中创建一个本类对象。
3.定义一个共有的方法将创建的对象返回。

单例模式有三种类型:饿汉式、懒汉式、加强版的懒汉式。

一、饿汉式

public class Hungry {
	// 将构造器置为私有
	private Hungry() {
	};

	// 在本类中创建一个本类的对象
	private static final Hungry single = new Hungry();

	// 提供一个public方法,供其他类获得上面构造的对象
	public static Hungry getInstance() {
		return single;
	}
	
	//测试函数
	public void connectDB() {
		System.out.println("连接数据库成功!");
	}
}

测试类:

public class Test {
	public static void main(String[] args) {
		// Hungry hungry=new Hungry();//如果这样写的话是有错误提示的,因为Hungry的构造函数是私有的。
		Hungry.getInstance().connectDB();// 可以直接通过getInstance方法获得该类唯一的对象
	}
}

二、懒汉式

public class Lazy {
	//私有构造器
	private Lazy() {};
	//唯一对象
	private static Lazy single=null;
	//外部获得该对象的方法
	public Lazy getInstance() {
		if(single==null) {
			single=new Lazy();			
		}
		return single;
	}
}

懒汉式将唯一类的生成从成员函数的初始化推迟到方法中。饿汉式中的single是在Hungry类被装载进jvm中就被初始化成类。而这里被初始化成null。

这样如果该对象没有被用到过,那么single就不会生成对象,尽最大可能节约内存。

而且因为single会在之后赋值,所以声明时没有使用final关键字。

但是如果在多线程中,这个方式可能会使内存中存在多个对象,所以这种方式一般很少用。比如执行完了if判断语句就转向其他线程的if语句了,然后两个都判断为false,那么接下来就会生成两个对象。

三、迭代后的懒汉式

为了解决这个方法,就使用同步,为getInstance方法添加关键字synchronized :

public synchronized Lazy getInstance() {
		if(single==null) {
			single=new Lazy();			
		}
		return single;
	}

但是这样每次调用此方法时都要判断锁,会严重降低效率,所以把这个关键字放在里面修饰语句:

public  Lazy getInstance() {
		synchronized(Lazy.class) {
			if(single==null) {
				single=new Lazy();			
			}
			return single;
		}
	}

但其实好像并没有什么区别,还是每次调用的时候都要判断锁,如何做到只有当创建对象的时候才加锁,当对象不为空的时候就直接返回对象呢?最终的解决方案:

那就是在加锁前判断对象是否为Null:

public  Lazy getInstance() {
		if(single==null) {
			synchronized(Lazy.class) {
				if(single==null) {
					single=new Lazy();			
				}
                                return single;				
			}
		}
		return single;
	}

第一次判断是为了提升效率,当single对象已经生成就不需要检测锁,直接返回对象。

然后同步代码块保护线程安全,如果多个线程都运行了第一个判断后,进入到同步代码块,那么第二个if是为了这多个线程中只有一个生成对象,其他线程可以在第二个if外获得该线程生成的对象。

参考:【JAVA单例模式详解】 - 狂盗一枝梅 - 博客园

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值