单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。(让类自身责任保存它的唯一实例)
单例模式确保对象只有一个,例如数据库连接池或者线程池,只需要一个,不需要new很多,但是要考虑线程安全的问题。
结构图
要点:
1.利用static的特性,static的属性和方法是属于类的,它不是靠new出来的,只要类被加载,它就被加载,有且只有一个。
2.构造方法的权限要是private,确保外界不能通过new来获取实例
单例模式又分为饿汉式和懒汉时
1、饿汉式:自己被加载时就将自己实例化。
package com.maggie.singleton; public class Singleton { private static Singleton s = new Singleton(); //类 一加载s就存在,所以为饿汉式 private Singleton() {} //构造函数private,确保外界不能通过new来获取实例 public static Singleton getInstance() { return s; } }
2、懒汉式:在第一次被引用时,才会将自己实例化
懒汉式面临着多线程访问的安全性问题,需要做双重锁来保证安全
package com.maggie.singleton; public class Singleton2 { private static Singleton2 s = null; //实例一开始为null,类加载时不会也被加载,需要调用getInstance时实例才能被加载 private Singleton2() {} public static Singleton2 getInstance() { //当多线程进入到这个方法中会导致线程安全问题 if(s == null) { s = new Singleton2(); } return s; } }
双重锁来确保懒汉式线程安全
package com.maggie.singleton; public class Singleton3 { private static Singleton3 instance; private Singleton3() { } public static Singleton3 getSingleton() { /* * if (instance == null) 为什么两次判断? * 因为如果 同时有两个线程调用getInstance()时,都可以通过第一次instance== null判断 * 然后进入第二次的instance == null,只能一个线程进入, * 其中有一个线程进去了,instance !=null,另一个线程就不用new。 */ if (instance == null) { synchronized (Singleton.class) { // 不能锁instance,因为一开始instance=null if (instance == null) { instance = new Singleton3(); } } } return instance; } }