《大话设计模式》读书笔记:单例模式与Java同步锁synchronized

单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。在单例模式下,类本身负责保存它的唯一实例,这个类必须保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。单例模式的类中,构造方法(函数/体)被设为private,从而堵死了外部实例化该类的可能。同时,在类中提供一个静态方法负责提供该类的唯一实例,并在实例不存在的情况下试图初始化它。

 

下面的示例展示了单例模式的典型实现:

public class Singleton {
    private static Singleton instance;
   
    private Singleton() {
       
    }
   
    public static Singleton getInstance(){
        if (instance == null) {
            instance = new Singleton();
        }
       
        return instance;
    }
}

 

上述的示例中,单例类中的实例在第一次被引用时才被初始化,这种类型的单例类称为“懒汉式”。单例模式有两种类型,另一种叫“饿汉式”,是指单例类的实例在加载时就被初始化,如下所示:

public class Singleton {
    private static Singleton instance = new Singleton();
   
    private Singleton() {
       
    }
   
    public static Singleton getInstance(){
        return instance;
    }
}

 

单例模式主要用在类需要且仅需要被初始化一次的场合,如UI界面中的工具栏、Android应用中的警告框等等。在单线程程序中,通过上述两种方式生成的单例类就已经可以满足要求了。但是在多线程环境下,情况就麻烦一些:如果多个线程同时实例化某懒汉式的单例类,那么就有可能在单例类内部多次初始化实例,造成单例模式失效。因此,对于多线程程序中的懒汉式单例,还需要对其加锁,确保线程安全。

 

关于Java的同步锁关键字synchronized ,可以参见如下的链接:

http://www.cnblogs.com/devinzhang/archive/2011/12/14/2287675.html

 

简单地说,synchronized 关键字的用法,主要分为两类:

一是方法定义时,加在方法名之前,形如:synchronized   methodName(params){ … };

二是声明同步块,形如:synchronized(this) { … }。

其作用是给修饰的方法或者代码块加上同步锁。当一个线程执行到这个方法或者代码块的时候,该部分被锁定,之后的其它执行到这些代码的线程被阻塞,直到上一个线程执行完毕,释放同步锁。

 

如下的代码是线程安全的懒汉式单例类的实现:

public class Singleton {
    private static Singleton instance;
    private final static Object syncLock = new Object();
   
    private Singleton() {
       
    }
   
    public static Singleton getInstance(){
        if (instance == null) {
            synchronized (syncLock) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
       
        return instance;
    }
}

 

需要注意的是,synchronized同步块处括号中的锁定对象采用的是一个无关的Object类实例。将它作为锁而不是通常synchronized所用的this,其原因是getInstance方法是一个静态方法,在它的内部不能使用未静态的或者未实例化的类对象(避免空指针异常)。同时也没有直接使用instance作为锁定的对象,是因为加锁之时,instance可能还没实例化(同样是为了避免空指针异常)。

此外,单例类中不建议将getInstance方法修饰为synchronized方法,其原因是一旦这样做了,其效果就跟《大话设计模式》书中21.5小节的示例是一样的了。这种做法会在每次调用getInstance方法时,都需要加锁,与上例相比效率更低。

    原文作者:java锁
    原文地址: https://blog.csdn.net/sadfishsc/article/details/8007934
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞