public class AppConfig{
private String parameterA;
private String parameterB;
public String getParameterA(){
return parameterA;
}
public String getParameterB(){
return oarameterB;
}
public AppConfig(){
readConfig();
}
private void readConfig(){
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.printStrackTrace();
}
}
}
}
}
public class Client{
public static void main(String[] args){
AppConfig config=new AppConfig();
String paramA=config.getParameterA();
String paramB=config.getParameterB();
System.out.println("paramA="+paramA+",paramB="+paramB);
}
}
存在的问题:
● 如果在系统运行中,多处都需要使用配置文件的内容,也就是说有很多地方都需要创建AppConfig对象的实例
● 即在系统运行时,系统会存在很多个AppConfig的实例对象
● 如果配置文件较大,将是对资源的很大的浪费
解决方案——单例模式
● 单例(Singleton)模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
● Singleton模式解决问题十分常见:创建一个唯一的变量(对象)
● Singleton模式是设计模式中最为简单、最为常见、最容易实现,也是最应该熟悉和掌握的模式。
● Singleton模式只包含一个角色,就是Singleton。
● Singleton拥有一个私有构造函数,确保用户无法通过new直接实例它。
● 该模式中包含一个静态私有成员变量instance与静态公有方法GetInstance。GetInstance方法负责检验并实例化自己,然后存储在静态成员变量中,以确保只有一个实例被创建。
单例类
class Singleton{
private static Singleton instance;
private Singleton(){
//构造方法为private,外界就不能利用new创建此类型的实例
}
public static Singleton GetInstance(){
if(instance == null){
//如果实例不存在则new一个新实例,否则返回已有的实例
instance = new Singleton();
}
return instance;
}
public static void main(String[] args){
//Singleton s0 = new Singleton();
//错误,外界不能通过new来创建此类型实例
Singleton s1 = Singleton.GetInstance();
Singleton s2 = Singleton.GetInstance();
if(s1 == s2)//判断2次实例化后对象的结果是实例相同
System.out.print("两个对象是相同的实例");
else
System.out.print("两个对象是不同的实例");
}
}
● 单例模式的特点:
◇单例类只能有一个实例。
◇单例类必须自己创建自己的唯一实例。
◇单例类必须给所有其它对象提供这一实例。
● 单例模式的优点:
◇可以办证唯一的实例。
◇保证对唯一实例的受控访问。
多线程时的单例
public class Singleton{
private static Singleton instance;
private static final Object syncRoot = object();
//程序运行时创建一个静态只读的进程辅助对象
public static Singleton getInstance(){
synchronized(syncRoot)
//在同一个时刻加了锁的部分程序只有一个线程可以进入
{
if(instance == null)
{ instance = new Singleton();}
}
System.out.println("singleton创建");
return instance;
}
public static void main(String[] args){
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
if(singleton1 == singleton2){
System.out.print("该对象的字符串表示形式:");
System.out.print("singleton1:"+singleton1.toString());
System.out.print("singleton2:"+singleton2.toString());
}//在同一个时刻加了锁的部分程序只有一个线程可以进入
}
}
问题:
● 上面的代码在每次调用getInstance方法时都需要同步,降低了性能
● 解决:双重锁定
不用让线程每次都加锁,而只是在实例未被创建的时候加锁,同时也保证多线程的安全。
public 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 static void main(String[] args){
SingletonDCL singleton1=SingletonDCL.getInstance();
SingletonDCL singleton2=SingletonDCL.getInstance();
System.out.println("singleton1 == singleton2?"+(singleton1==singleton2));
System.out.println("该对象的字符串表示形式:");
System.out.println("singleton1:"+singleton1.toString());
System.out.println("singleton2:"+singleton2.toString());
}
}