设计模式之单例模式
单例模式
1.单例模式定义:保证一个类只有一个实例,并且提供他一个全局的访问点。
2.单例模式功能:用来保证这个类在运行期间只会创建出一个类实例,并提供一个全局的唯一访问这个类实例的访问点。
3.单例模式的范围:是一个ClassLoader及其子类ClassLoaer的范围。
4.单例模式的命名:一般建议单例模式的方法命名为getInstance();
5.饿汉式单例模式:
public class Account {
//定义一个变量来存储创建好的实例,直接在这里创建实例,只会创建一次。
private static Account intance = new Account();
/**
* 私有化构造方法,好在内部控制创建实例的数目
*/
private Account(){
}
/**
* 定义一个方法微客户端提供类实例
*/
public static Account getIntance(){
//直接使用已创建好的实例
return intance;
}
}
上面的例子中,在这个类被加载时,静态变量instance会被初始化,此时类的私有构造子会被调用。这时候,单例类的唯一实例就被创建出来了。
饿汉式其实是一种比较形象的称谓。既然饿,那么在创建对象实例的时候就比较着急,饿了嘛,于是在装载类的时候就创建对象实例。
饿汉式是典型的空间换时间,当类装载的时候就会创建类的实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断,节省了运行时间。
6.懒汉式单例模式:
/**
* 懒汉式
*
*/
public class Account2 {
/**
* 定义一个变量来存储创建好的实例
*
*/
private static Account2 instance = null;
/**
* 私有构造方法
*/
private Account2(){
}
/**
* 定义一方法为客户端创建实例
*
*/
public static synchronized Account2 getInstance(){
//判断存储的类的实例是否有值
if(instance == null){
//如果没有。就创建一个实例,并赋值
instance = new Account2();
}
return instance;
}
7.读取应用配置文件,单例模式实现
/**
* 读取应用配置文件,单例模式实现
*
*/
public class AppConfig {
/**
* 定义一个变量来存储创建好的实例,直接在这里创建类实例,只会创建一次。
*
*/
private static AppConfig instance = new AppConfig();
/**
* 定义一个方法来为客户端提供Appconfig 的实例。
*/
public static AppConfig getIntance() {
return instance;
}
/**
* 用来存放配置文件中参数user的值
*/
private String user;
public String getUser() {
return user;
}
/**
* 用来存放配置文件中参数pass的值
*/
private String pass;
public String getPass() {
return pass;
}
private AppConfig() {
// 读取配置文件的方法
readConfig();
}
private void readConfig() {
Properties p = new Properties();
InputStream in = AppConfig.class.getResourceAsStream("Appconfig.properties");
try {
System.out.println("现在读取配置文件一次***************");
p.load(in);
// 把配置文件读出来的内容设置到属性上
this.user = p.getProperty("user");
this.pass = p.getProperty("pass");
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("出错了");
e.printStackTrace();
}
}
}
public class Test {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
AppConfig config = AppConfig.getIntance();
System.out.println(i+"user位:"+config.getUser()+"密码"+config.getPass());
}
}
}
总结:
1.饿汉式是线程安全的
2.如何实现懒汉式的线程安全
加上synchronize即可
3.双重检查加锁:
所谓双重检查加锁指的是,并不是每次进入getIntance方法都需要同步,而是先不同步,进入方法后,先检查实例是否存在。如果不存在才会进入下面的同步块,进入同步块再次检查实例是否存在。如果不存在,就在同步的情况下创建一个实例,这是第二重检查,这样一来只需要同步一次了,从而减少了多次在同步情况下判断所浪费的时间。
双重检查加锁的实现会使用一个关键字volatile,他的意思是被volatile修饰的变量值将不会被本地线程缓存,所有对该变量的读写都是操作共享内存,从而保证了多线程能正确的处理该变量。