单例模式 java-A4纸画出单例模式的UML图
拿出一张A4纸画出单例模式的UML图(面试时如果被问到设计模式相关问题,能先画出UML图肯定是加分项):
单例模式UML图
估计很多小伙伴都忘记怎么读UML图了吧?这里详细解释下:
单例模式具体实现细节,看英文解释会更直观:
1.The implementation involves a static member in the "Singleton" class,
静态成员变量instance
2.a private constructor
私有构造函数
3.a static public method that returns a reference to the static member.
public static修饰的返回一个实例对象的方法
一段简单的代码实现:
public final class Singleton {
//类一加载时实例就被创建
private static final Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
当然如果面试时仅仅写出上面的代码是远远不够的,面试官不会轻易让我们过关的,这只是刚刚热身,更深入的问题还在后面:
1.你知道懒加载吗?是怎么用在单例创建上的?有什么优势?
如果某个实例的创建(比如数据库连接池的创建)需要消耗很多系统资源,就需要引入懒加载机制。即上面的代码在类加载时就创建好了单例模式 java,如果在程序中始终没用到这个实例就会浪费很多系统资源。
为避免这种情况,就引入了懒加载机制,即在使用这个实例的时候才创建它。
引入懒加载后的单例实现代码如下(这就是我们常听到的“懒汉式”单例):
public class Singleton{
private static Singleton instance = null;
private Singleton(){
…
}
public static Singleton getInstance(){
if (instance == null)
//实例在调用getInstance()函数的时候才会创建
instance = new Singleton(); //1. A线程执行
return instance; //2.B线程执行
}
}
2.这个例子你考虑到线程安全了吗?什么是线程同步?什么是双重检查锁定?怎么用在单例上?
的确当引入多线程时,以上代码不是线程安全的:假设A线程执行代码1的同时,B线程执行代码2。此时,线程A可能会看到instance引用的对象还没有完成初始化。
通过Java语言的关键字synchronized实现线程同步,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。因此通过对函数getInstance()做同步处理来实现线程安全的初始化:
class Singleton
{
private static Singleton instance;
private Singleton()
{
...
}
public static synchronized Singleton getInstance()
{
if (instance == null)
instance = new Singleton();
return instance;
}
...
public void doSomething()
{
...
}
}
上面的代码是线程安全的一种实现,但是如果考虑到性能单例模式 java,synchronization是非常消耗资源的,一次只能有一个线程调用getInstance()方法,而getInstance方法在对象实例化之后无需再阻塞访问。即如果对象已经创建完成,只需要return 这个对象就OK了,不需要用syncronized同步。
因此进一步优化:先在非synchronized块检查object是否为null,是就直接return object,否则进入syncronized同步块创建object,这就成为双重锁机制(double locking mechanism).
代码实现如下:
//Lazy instantiation using double locking mechanism.
class Singleton
{
private static Singleton instance;
private Singleton()
{
System.out.println("Singleton(): Initializing Instance");
}
public static Singleton getInstance()
{
if (instance == null) //1.第一次检查
{
synchronized(Singleton.class)//2.加锁
{
if (instance == null) //3.第2次检查
{
System.out.println("getInstance(): First time getInstance was invoked!");
instance = new Singleton(); //4.实例化对象
}
}
}
return instance;
}
public void doSomething()
{
System.out.println("doSomething(): Singleton does something!");
}
}