单例模式(Singleton Pattern)
概述
单例设计模式,简单来说就是一个类始终只能产生一个对象。使用单例模式可以有效节省内存资源,在一些环境配置的类中,一个服务器的软件启动以后,只需要加载一次就可以了。例如多个程序读取一个配置文件时,建议把配置文件封装成对象。会方便操作其中数据,又要保证多个程序读到的是同一个配置文件对象,就需要该配置文件对象在内存中是唯一的。使用单例模式保证一个类在内存中的对象唯一性。
单例模式的实现步骤
- 私有化构造函数
- 创建私有并静态的本类对象
- 定义公有并静态的方法,返回该对象
饿汉式和懒汉式
饿汉式:在类加载的时候就创建好一个对象,以后每次都返回创建好的这个对象。
//饿汉式
class Single{
private Single(){
} //私有化构造函数。
private static Single s = new Single(); //创建私有并静态的本类对象。
public static Single getInstance(){ //定义公有并静态的方法,返回该对象。
return s;
}
}
懒汉式:一开始不创建对象,等需要用的时候才创建对象。在需要的时候才占用资源,懒加载对象。
//懒汉式(lazyload 延迟加载)
class Single{
private Single(){
}
private static Single s = null;
public static Single getInstance(){
if(s==null)
s = new Single ();
return s;
}
}
单例模式经典实现方法
方法一:
package com.singleton;
public class Single{
private Single(){
} //私有化构造函数。
private static Single s = new Single(); //创建私有并静态的本类对象。
public static Single getInstance(){ //定义公有并静态的方法,返回该对象。
return s;
}
}
方法二:
package com.singleton;
public class Single{
public static final Single s=new Single();
private Single(){
}
}
方法三:(枚举实现)
package com.singleton;
public enum SingleEnum{
INSTANCT;
}
单例模式的线程安全问题
在Web项目中,每个 HTTP Request 请求到 J2EE的容器上后都创建了一个线程,每个线程都要创建同一个单例对象。如果同时有多个线程访问程序,可能会出现多个对象实例,会造成业务逻辑混乱,数据不不一致等问题。
解决方法:
1) 使用同步方法:
public static synchronized Single getInstance()
2) 使用同步代码块:
synchronized (Single.class)
//使用同步代码块
class Single {
private static Single s = null;
//1) 把构造方法设置成私有的
private Single() {
}
//2) 提供一个公共的静态的方法产生对象
public static Single getInstance() {
if (s==null) {
synchronized (Single.class) { //判断同步锁,是需要消耗资源
if (s == null) { //必须加上
try {
Thread.sleep(5);
} catch (Exception e) {
e.printStackTrace();
}
s = new Single();
}
}
}
return s;
}
}
//使用同步方法
class Single {
private static final Single s= new Single();
// 限制住不能直接产生一个实例
private Single(){
}
public synchronized static Single getInstance(){
return s;
}
}