java设计模式--单列模式

单列模式定义:确保一个类只有一个实例,并提供一个全局访问点。

下面是几种实现单列模式的Demo,每个Demo都有自己的优缺点:

Demo1:

复制代码
/**
 * 单列模式需要满足下面三个条件:
 * 1.私有的构造函数
 * 2.私有的引用变量
 * 3.公开的静态方法(唯一获取该类单个实例的地方)
 * 
 * @author Administrator
 */
public class AmericaPresident
{
    private static AmericaPresident thePresident;
    
    /**
     * 功能:私有的构造函数
     */
    private AmericaPresident()
    {
    }
    
    /**
     * 功能:返回AmericaPresident对象
     * @return
     */
    public static AmericaPresident getPresident()
    {
        if(thePresident == null)
        {
            thePresident = new AmericaPresident();
        }
        
        return thePresident;
    }
}

Demo1 在多线程的时候可能会出现一些程序上的bug
复制代码

Demo2:

复制代码
为了解决上面Demo1在多线程时候的bug,可以做出以下的修改:

/**
 * 单列模式需要满足下面三个条件:
 * 1.私有的构造函数
 * 2.私有的引用变量
 * 3.公开的静态方法(唯一获取该类单个实例的地方)
 * 
 * @author Administrator
 */
public class AmericaPresident
{
    private static AmericaPresident thePresident;
    
    /**
     * 功能:私有的构造函数
     */
    private AmericaPresident()
    {
    }
    
    /**
     * 功能:返回AmericaPresident对象
     * @return
     */
    public static synchronized AmericaPresident getPresident()
    {
        if(thePresident == null)
        {
            thePresident = new AmericaPresident();
        }
        
        return thePresident;
    }
}

通过增加synchronized 关键字到getPresident()方法中,我们迫使每个线程在进入这个方法之前,
要先等候别的线程离开该方法。也就是说,不会有两个线程可以同时进入这个方法。

Demo2解决了多线程下的程序bug,但是又带了一个新的问题,同步一个方法可能造成程序执行效率
下降100倍。
复制代码


Demo3:

复制代码
/**
 * 单列模式需要满足下面三个条件:
 * 1.私有的构造函数
 * 2.私有的引用变量
 * 3.公开的静态方法(唯一获取该类单个实例的地方)
 * 
 * @author Administrator
 */
public class AmericaPresident
{
    private static AmericaPresident thePresident = new AmericaPresident();
    
    /**
     * 功能:私有的构造函数
     */
    private AmericaPresident()
    {
    }
    
    /**
     * 功能:返回AmericaPresident对象
     * @return
     */
    public static synchronized AmericaPresident getPresident()
    {
        return thePresident;
    }
}


Demo3使用"急切"创建实例,而不用延迟实例化的做法,如果应用程序总是创建并使用单列实例,或者
在创建和运行方面的负担不太繁重,就可以用"急切"的方法来创建单列。
利用这个做法,我们可以依赖JVM在加载这个类时马上创建此唯一的单列实例,JVM保证在任何线程
访问thePresident静态变量之前,一定先创建此实例。
复制代码


Demo4:

复制代码
用"双重检验加锁",在getPresident()中减少使用同步。

利用双重检查加锁(double-checked locking),首先检查是否实例已经创建了,如果尚未
创建,"才"进行同步。这样一来,只有第一次会同步。



/**
 * 单列模式需要满足下面三个条件:
 * 1.私有的构造函数
 * 2.私有的引用变量
 * 3.公开的静态方法(唯一获取该类单个实例的地方)
 * 
 * @author Administrator
 */
public class AmericaPresident
{
    private volatile static AmericaPresident thePresident;
    
    /**
     * 功能:私有的构造函数
     */
    private AmericaPresident()
    {
    }
    
    /**
     * 功能:返回AmericaPresident对象
     * @return
     */
    public static synchronized AmericaPresident getPresident()
    {
        if(thePresident == null)//检查实例,如果不存在,就进入同步区块
        {
            synchronized(AmericaPresident.class)//注意,只有第一次才彻底执行这里的代码
            {
                if(thePresident == null)//进入区块后,再检查一次,如果还是Null,才创建实例。
                {
                    thePresident = new AmericaPresident();
                }
            }
        }
        return thePresident;
    }
}

volatile关键字确保:当thePresident变量被初始化成AmericaPresident实例时,多个线程正确
处理thePresident变量。


如果性能是你关注的重点,那么这个做法可以帮你大大地减少getPresident()的时间消耗。
复制代码

 

原文地址:https://www.cnblogs.com/baiduligang/p/4247428.html