今天先介绍一下单例模式。
概念:
单例模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点。
实现:
我们可以在程序中(这里指单例对象外)设置计数器,从而保证只创建一个对象。此种方法只是提供创建以及访问权限,并未从本质上扼制多次创建。更好的方法是在实例类中保证只有一个实例对象。通过一个静态全局数据成员和一个静态全局方法来达到单例模式目的。下面是段最简单的单例模式Java代码:
package Pattern; class Singleton { private static Singleton mySingleton; private Singleton() { System.out.println("正在创建单例模式!"); }; public static Singleton GetInstance() { if (null == mySingleton) mySingleton = new Singleton(); return mySingleton; } } public class Pattern { public static void main(String[] args) { try { if(Singleton.GetInstance()!=null) System.out.println("成功创建单例模式对象!"); if(Singleton.GetInstance()!=null) System.out.println("成功创建单例模式对象!"); } catch (Exception e) { System.out.println("Java异常发生!"); } } }
程序中有一个private型的构造函数,保证外部通过new创建的该类对象都没有实例化,都指向null,因为private型的构造函数只能在类中访问。当然有其他方式控制只创建一个实例对象。
上述代码存在的问题是不能在多线程的环境下运行。可能对于某个线程null == mySingleton成立,进行创建;在此同时另外一个线程null == mySingleton也成立,从而也要创建实例对象,从而在内存中存在两个副本,违背单例模式原则。可以用synchronized来保证某时刻只能有一个线程可以访问对象或方法。如下:
package Pattern; class Singleton { private static Singleton mySingleton; private Singleton() { System.out.println("正在创建单例模式!"); }; public static synchronized Singleton GetInstance() { if (null == mySingleton) mySingleton = new Singleton(); return mySingleton; } } public class Pattern { public static void main(String[] args) { try { if(Singleton.GetInstance()!=null) System.out.println("成功创建单例模式对象!"); if(Singleton.GetInstance()!=null) System.out.println("成功创建单例模式对象!"); } catch (Exception e) { System.out.println("Java异常发生!"); } } }
上述代码能保证使用多线程,但不是总要求同步的,从而降低了程序的效率。可以尝试直接初始化mySingleton,然后提供访问接口,从而保证线程安全又避免总要求同步。代码如下:
package Pattern; class Singleton { private static Singleton mySingleton=new Singleton(); private Singleton() { System.out.println("正在创建单例模式!"); }; public static synchronized Singleton GetInstance() { if (null == mySingleton) mySingleton = new Singleton(); return mySingleton; } } public class Pattern { public static void main(String[] args) { try { if(Singleton.GetInstance()!=null) System.out.println("成功创建单例模式对象!"); if(Singleton.GetInstance()!=null) System.out.println("成功创建单例模式对象!"); } catch (Exception e) { System.out.println("Java异常发生!"); } } }
此处有个语言小知识:Java中,在类内部可以通过非静态构造函数来构造静态实例对象。这点语言知识以前忽略了。但是此种方法是在类加载时就完成实例化,我们知道在Java中是在最开始的地方即完成静态成员的初始化,但也有可能其他方法导致多次加载,从而存在不同实例时间段。有大牛建议用下面的代码,但暂时有个语法错误,待改正!欢迎大家指导!在此感激不尽!
package Pattern; public class Singleton { private volatile static Singleton mySingleton; private Singleton() { System.out.println("正在创建单例模式!"); }; public static Singleton GetInstance() { if (mySingleton == null) { synchronized (Singleton.class) { if (mySingleton == null) { mySingleton = new Singleton(); } } } return mySingleton; } } public class Pattern { public static void main(String[] args) { try { if (Singleton.GetInstance() != null) System.out.println("成功创建单例模式对象!"); if (Singleton.GetInstance() != null) System.out.println("成功创建单例模式对象!"); } catch (Exception e) { System.out.println("Java异常发生!"); } } }