确保某个类有且仅有一个对象的场景,避免产生多个对象消耗过多资源。例如:访问io和数据库资源,这时就要考虑使用单例模式。
2:UML图
关键点:
1:构造方法为private(该类不能通过new的方式产生对象)
2: 通过静态方法或枚举返回单例对象
3:确保在多线程环境下,产生的对象只有一个
4:确保单例对象在反序列化时,不会产生新对象
3:代码举例
3.1 饿汉模式:
public class Singleton2{
private Singleton2(){
}
private static final Singleton2 single2=new Singleton2();
public static Singleton2 getInSingleton2(){
return single2;
}
}
1)原始:
public class Singleton {
//1: 懒汉模式,在类第一次调用自己时实例化自己
private Singleton(){
}
private static Singleton singleton=null;
/**
* 有线程安全问题
* @return
*/
public static Singleton getInstance(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
2)解决方案1:
public class Singleton {
//1: 懒汉模式,在类第一次调用自己时实例化自己
private Singleton(){
}
private static Singleton singleton=null;
/**
* 好像性能有些问题
* @return
*/
public static synchronized Singleton getInstance(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
3)解决方案2:DCL- 双重检查锁定
public class Singleton {
//1: 懒汉模式,在类第一次调用自己时实例化自己
private Singleton(){
}
private static Singleton singleton=null;
public static Singleton getInstance(){
if(singleton==null){
synchronized (Singleton.class) {
if(singleton==null){
singleton=new Singleton();//1
}
}
}
return singleton;
}
}
双重检查锁定(DCL)-存在指令重排序的问题:
注释1处:可能指令重排序,导致有一个线程会获取一个初始化一半的singleton,应该private volatile static Singleton singleton=null;
singleton=new Singleton();
a: 给Singleton实例分配堆内存
b: 调用Singleton构造函数
c: 将singleton指向分配的内存空间
b依赖于a,c依赖于a,b,c之间无依赖,导致执行顺序:
a-b-c: 没毛病
或
a-c-b:
刚好执行完a-c,这时,线程切换到别的线程,这时singleton非空,执行会有问题,不好排查。
private volatile static Singleton singleton=null;
public class Singleton1{
private static class LazyHolder{
private static final Singleton1 INSTANCE=new Singleton1();
}
private Singleton1(){
}
public static final Singleton1 getInstance(){
return LazyHolder.INSTANCE;
}
}
3.3 枚举方式
public enum SingletonEnum {
INSTANCE;
private Person person=new Person();
public Person getPerson() {
return person;
}
public class Person{
}
}
3.4 反序列化
public class Singleton implements Serializable{
private static final long serialVersionUID=-1L;
protected Object readResolve() {
return singleton;
}
public class SaveAndRead {
public static void main(String[] args){
Singleton mSingleton= Singleton.getInstance();
System.out.println("序列化前对象:"+mSingleton.hashCode());
try {
FileOutputStream fos=new FileOutputStream(new File("123.txt"));
ObjectOutputStream oos =new ObjectOutputStream(fos);
oos.writeObject(mSingleton);
oos.close();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
FileInputStream fis =new FileInputStream(new File("123.txt"));
ObjectInputStream ois =new ObjectInputStream(fis);
Singleton singleton=(Singleton)ois.readObject();
ois.close();
fis.close();
System.out.println("反序列化后对象:"+singleton.hashCode());
} catch (Exception e) {
}
}
}
3.5 容器单例模式
public class SingletonManager{
private static Map<String, Object> objMap=new HashMap<String, Object>();
private SingletonManager(){
}
public static void addService(String key, Object instance){
if(!objMap.containsKey(key)){
objMap.put(key, instance);
}
}
public static Object getService(String key){
return objMap.get(key);
}
}
4:android中的单例模式
4.1 frameworks/base/core/java/android/view/accessibility/AccessibilityManager.java
/**
* Get an AccessibilityManager instance (create one if necessary).
*
* @param context Context in which this manager operates.
*
* @hide
*/
public static AccessibilityManager getInstance(Context context) {
synchronized (sInstanceSync) {
if (sInstance == null) {
final int userId;
if (Binder.getCallingUid() == Process.SYSTEM_UID
|| context.checkCallingOrSelfPermission(
Manifest.permission.INTERACT_ACROSS_USERS)
== PackageManager.PERMISSION_GRANTED
|| context.checkCallingOrSelfPermission(
Manifest.permission.INTERACT_ACROSS_USERS_FULL)
== PackageManager.PERMISSION_GRANTED) {
userId = UserHandle.USER_CURRENT;
} else {
userId = UserHandle.myUserId();
}
sInstance = new AccessibilityManager(context, null, userId);
}
}
return sInstance;
}
4.2 frameworks/base/core/java/android/text/Editable.java