本文共 3682 字,大约阅读时间需要 12 分钟。
单例模式(Singleton)
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
例子:配置文件
源代码:
public class AppConfig{ private String parameterA; private String parameterB; public String getParameterA() { return parameterA; } public String getParameterB() { return parameterB; } public AppConfig() { readConfig(); } private void readConfig() { // TODO Auto-generated method stub Properties p=new Properties(); InputStream in=null; try { in=AppConfig.class.getResourceAsStream("AppConfig.properties"); p.load(in); this.parameterA=p.getProperty("paramA"); this.parameterB=p.getProperty("paramB"); }catch(IOException e) { System.out.println("装载配置文件出错"); e.printStackTrace(); }finally { try { in.close(); }catch(IOException e) { e.printStackTrace(); } }}}public class main{ public static void main(String[] args) { Scanner sc=new Scanner(System.in); AppConfig config=new AppConfig(); String paramA=config.getParameterA(); String paramB=config.getParameterB(); System.out.println("paramA="+paramA+",paramB="+paramB); }}
问题:系统运行时,会出现很多AppConfig的实例对象,其实用户只想出现一次,造成资源浪费。
解决方法:单例模式
让类自身只提供它的一个实例,并且只提供一个访问它的全局访问点。创建一个唯一的变量对象。
class Singleton{ private static Singleton instance; private Singleton() { //构造方法为private,外界就不能利用new创建此类型的实例 } public static Singleton GetInstance() {//获得本类实例的唯一全局访问点 if(instance==null) { //如果实例不存在则new一个新实例,否则返回已有的实例 instance=new Singleton(); } return instance; } }public class main{ public static void main(String[] args) { Scanner sc=new Scanner(System.in); /*Singleton s0=new Singleton()*/ //错误,外界不能通过new创建此类型 Singleton s1=Singleton.GetInstance(); Singleton s2=Singleton.GetInstance();if(s1==s2)//判断两次实例化后对象的结果是实例相同{ System.out.println("两个对象是相同的实例");}else{ System.out.println("两个对象是不同的实例");} }}
多线程的程序,多个线程同时访问Singleton类,调用GetInstance()方法,有可能造成创建多个实例。
解决:在执行new创建实例的地方加上锁,同时在锁定之前判断下是否为null,这样如果已经创建就不用进入锁了。 java使用synchronized上锁class Singleton{ private static Singleton instance; private static final Object syncRoot=new Object(); //程序运行时创建一个静态只读的进程辅助对象 private Singleton() { //构造方法为private,外界就不能利用new创建此类型的实例 } public static Singleton GetInstance() {//获得本类实例的唯一全局访问点 synchronized(syncRoot)//在同一个时刻加了锁的部分程序只有一个线程可以进入 { if(instance==null) { //如果实例不存在则new一个新实例,否则返回已有的实例 instance=new Singleton(); }//不直接synchronized(instance),因为若instance为空,则无法对它加锁 } System.out.println("singleton创建"); return instance; }}//使得对象实例由最先进入的那个线程创建,以后的线程在进入时不会再去创建对象实例了。由于//synchronized保证了多线程环境下的同时访问也不会造成多个实例的生成。public class main{ public static void main(String[] args) { Singleton s1=Singleton.GetInstance(); Singleton s2=Singleton.GetInstance();if(s1==s2)//判断两次实例化后对象的结果是实例相同{ System.out.println("该对象的字符串表示形式:"); System.out.println("s1:"+s1.toString()); System.out.println("s2:"+s2.toString());} }}
每次调用getinstance方法时都需要锁定,降低了性能。
双重锁定
不用让线程每次都加锁,而是在实例未被创建的时候再加锁处理,同时也能保证多线程的安全。
class SingletonDCL{ private volatile static SingletonDCL singleton; private SingletonDCL() { } public static SingletonDCL GetInstance() { if(singleton==null) {//各类加锁,类的所有对象用同一把锁 synchronized(SingletonDCL.class) { if(singleton==null)//多线程进入,防止第二个线程创建实例,破坏单例原则 { singleton=new SingletonDCL(); } } } System.out.println("singleton创建"); return singleton; }}public class main{ public static void main(String[] args) { SingletonDCL s1=SingletonDCL.GetInstance(); SingletonDCL s2=SingletonDCL.GetInstance(); System.out.println("s1==s2?"+(s1==s2)); System.out.println("该对象的字符串表示形式:"); System.out.println("s1:"+s1.toString()); System.out.println("s2:"+s2.toString());}}
单例模式分类
转载地址:http://txyzi.baihongyu.com/