单例模式
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修饰的变量值将不会被本地线程缓存,所有对该变量的读写都是操作共享内存,从而保证了多线程能正确的处理该变量。