JAVA 与 MyCat(2) 单例模式

来源:互联网 发布:数据库的设计原则答案 编辑:程序博客网 时间:2024/06/06 23:56

通过mycat来学习java了^^。


接前一篇:http://blog.csdn.net/john_chang11/article/details/78668667


MycatServer server = MycatServer.getInstance();

获取MyCat实例,其实就是读取配置文件,并验证正确性等。

MyCat实例必须全局唯一,所以这里涉及到JAVA的单实例模式,就是一个类只有唯一一个实例对象存在。先来看看mycat源码是怎么做的:

public class MycatServer {private static final MycatServer INSTANCE = new MycatServer();public static final MycatServer getInstance() {return INSTANCE;}private MycatServer() {......}}

首先,将构造方法定义成私有的,这样外界不能再实例化该类。然后,提供一个公有的静态方法,使外界只能通过该方法来获取类实例,该方法返回一个类型为类本身的静态属性值,该属性值在类加载时调用私有构造方法初始化。这就保障了,该类只有唯一一个实例对象的存在。

上面这种写法是单实例创建的饿汉模式,线程安全,但浪费内存空间,不过mycat要运行MycatServer类是肯定要装载的,所以源码里这样用也没有问题。单实例模式的写法还有别的写法,一起看看。


1.懒汉,省内存空间,但线程不安全,不推荐使用

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

使用时才初始化实例,所以省内存,但也影响了速度,而且线程不安全,只能在单线程环境下可行,不推荐使用。


2.懒汉,线程安全,但效率低,不推荐使用

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

这种方式也是在使用时才初始化,省内存,但每次调用getInstance()方法时,都需要获取同步锁,非常耗时,也不推荐使用。


3.懒汉,双重检查锁,依然有问题,不推荐使用

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

这种方式是对第2种的改进,只在第一次创建实例时需要同步锁,以后不再需要,大大提高了性能。但是这种方式依然有问题,这与JAVA内存模式的无序写入有关,即使使用volatile,也依然有问题。为了不偏离主题,本文不详细介绍这些问题的原因,有兴趣可以参考:http://blog.csdn.net/chenchaofuck1/article/details/51702129和http://blog.csdn.net/axman/article/details/1089196

4.饿汉,线程安全,效率高,但内存使用率低,推荐使用

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

这种方式,是利用JVM的机制:静态实例的初始化是ClassLoader经由[ThreadSafe]来完成,所以是线程安全的。该方法去除的同步,且类加载时就创建实例,所以效率高。但由于是类加载时就创建实例,所以内存使用率低,不过既然使用该类一般就会初始化该类的一个实例,所以该仍然推荐使用。


5.静态内部类,集所有优点于一身,推荐使用

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

内部类不会随主类加载而加载,只有在第一次使用时才会加载,而单实例又是内部类的静态实例,所以用这种方式获取单实例,即是lazy loading,节省内存,又是线程安全且不需要同步锁的。所以用这种方式获取单实例最好。不过,使用时才创建实例,会对第一次调用产生影响,所以这种方式与第4种方式,可以互补使用:如果单实例类一定需要初始化,就用第4种,如果不一定需要初始化,就用第5种。