创建模式——单例模式

来源:互联网 发布:缠中说禅炒股软件 编辑:程序博客网 时间:2024/05/16 06:37

1、什么是单例模式

Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。在很多操作中,比如建立目录 数据库连接(当然多使用连接池)都需要这样的单线程操作。Singleton模式就为我们提供了这样实现的可能。使用Singleton的好处还在于可以节省内存,因为它限制了实例的个数,有利于Java垃圾回收(garbage collection)。

Singleton主要是在类自身定义一个静态的自身实例作为属性,并私有化,最后通过一个公有的方法获得这个实例。用static声明的变量在整个程序运行过程中,只会在编译时创建一次,所以保证了实例的单例化。

推荐一篇关于单例模式的文章:点击打开链接


2、饿汉形式

饿汉形式是在编译时为声明一个对象,并且实例化,这样做无论程序是否调用这个实例,它都一直存在于内存中。但这样不会出现在运行过程中创建出多个实例的错误。
/** * 饿汉方式  */public class Singleton {private static Singleton sgt = new Singleton();        private Singleton (){}//构造函数的隐藏public static Singleton getSingleton(){return sgt;}}

3、懒汉方式

懒汉形式是在运行过程中,当程序需要这个类的一个实例时,才会开辟内存并实例化。但当程序有多个线程同时访问这段程序,有可能会创建多个实例,所以必需加上synchronized关键字,防止上述错误的发生。

/** * 懒汉方式 */public class Singleton {private static Singleton sgt = null;        private Singleton (){}//构造函数的隐藏</span>public synchronized static Singleton getSingleton() {//第一把同步锁if (sgt == null) {synchronized (Singleton.class) {//第二把同步锁是为了防止java重排序时,导致产生多个实例sgt = new Singleton();}}return sgt;}}

4、使用java反射机制可以创建多个实例

public static void main(String[] args) throws Exception  {Class clazz=Singleton.class;//获得Singleton的字节码Constructor<Singleton> cons=clazz.getDeclaredConstructor();//获得默认的构造函数cons.setAccessible(true);//将这个函数的访问权限打开,不再是privateSingleton sgt1 = cons.newInstance();Singleton sgt2 = cons.newInstance();System.out.println(sgt1);System.out.println(sgt2);//运行结果发现这个两个变量的引用地址不一样,说明产生了两个实例sgt1=Singleton.getSingleton();sgt2=Singleton.getSingleton();System.out.println(sgt1);System.out.println(sgt2);//运行结果发现这个两个变量的引用地址是一样,说明产只产生了一个实例}

当使用反射机制去创建一个实例时,是直接去内存加载这个类的字节码,而通常所指的单例是由jvm自动去加载字节码,再通过static private等修饰手法使某个类在运行时只产生一个实例,而反射相当于绕过了【平常使用static private等修饰手法限制实例的产生】这一过程,自己拿着字节码就去产生一个新的实例了。这样就使得单例不再是单例了。

5、单例模式的优点与注意事项

5.1优点

1、单例模式只会产生一个对象,在内存中也有一个,节省内在空间
2、避免频繁的创建和销毁对象,可以提高内部运行性能
3、可以全局讯问

5.2注意

1、使用单例设计模式时,就应该考虑其反制机制和原型模式之间的冲突
2、不要断开引用变量与单例类对象之间的联系
3、使用高并发操作时,注意线程安全
4、单例是将其构造函数给隐藏了的,所以一般单例类是不能够被继承的,因为子类在实例化的过程会调用父类的构造函数,而单例没有构造函数提供给子类调用,所以单例是不能够被继承的。但存在一种<<不完全的单例类>>,它的构造函数是公开的。这方面更深入的研究可参考《java与模式》一书

6、与原型模式的冲突

在java中,基本上要实现了Cloneable这一接口,重写clone()这一方法,就完成了一个原型类,但如果一个单例类也这样去做,就破坏了原有单例机制,可以用克隆的手法直接忽略了构造函数的限制。因为对象的克隆是通过Object类的clone这一个本地方法去完成的,它可以直接操作内存中的数据,去复制一份一模一样的对象,根本不会去调用构造函数,原型模式甚至可以忽略类中所有访问限制(private,protect),所以单例模式与原型模式是一对相矛盾的设计模式。
public static void main(String[] args) throws Exception  {Singleton sgt1,sgt2;sgt1=Singleton.getSingleton();sgt2=(Singleton) sgt1.clone();System.out.println(sgt1);System.out.println(sgt2);//运行结果发现这个两个变量的引用地址不一样,说明产只产生了两个实例}


1 0
原创粉丝点击