单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
Singleton类拥有一个私有构造函数,确保用户无法通过new直接实例它。
该模式包含一个静态私有成员变量instance与静态公有方法GetInstance()。GetInstance方法负责检验并实例化自己,然后存储在静态成员变量中,以确保只有一个实例被创建。
public class Text {
public static void main(String[] args) {
// TODO Auto-generated method stub
Singleton s1=Singleton.GetInstance();
Singleton s2=Singleton.GetInstance();
if(s1==s2)
{
System.out.println("两个对象是相同的实例");
}
else
System.out.println("两个对象是不同的实例");
}
}
class Singleton
{
private static Singleton instance;
private Singleton()
{
}
public static Singleton GetInstance()
{
if(instance==null)
{
instance=new Singleton();
}
return instance;
}
}
多线程时的单例
多线程的程序中,多个线程同时访问Singleton类,调用GetInstance()方法,会有可能造成创建多个实例
解决:在执行new创建实例的地方加上锁,同时在锁定之前判断下是否为null,如果已经创建就不用进入锁了
public class Text {
public static void main(String[] args) {
// TODO Auto-generated method stub
Singleton s1 = Singleton.GetInstance();
Singleton s2 = Singleton.GetInstance();
if (s1 == s2) {
System.out.println("两个对象是相同的实例");
} else
System.out.println("两个对象是不同的实例");
}
}
class Singleton {
private static Singleton instance;
private static final Object syncRoot = new Object(); // 程序运行时创建一个静态只读的进程辅助对象
private Singleton() {
}
public static Singleton GetInstance()
{
synchronized(syncRoot)
{
if(instance==null)
{
instance=new Singleton();
}
}
return instance;
}
}
缺点:每次调用GetInstance方法时都需要加锁同步,降低了性能
解决:双重锁定。不用让线程每次都加锁,而只是在实例未被创建的时候加锁,同时也能保证多线程的安全。
双重锁定
public class Text {
public static void main(String[] args) {
// TODO Auto-generated method stub
Singleton s1 = Singleton.GetInstance();
Singleton s2 = Singleton.GetInstance();
if (s1 == s2)
{
System.out.println("两个对象是相同的实例");
} else
System.out.println("两个对象是不同的实例");
}
}
class Singleton
{
private static Singleton instance;
private static final Object syncRoot = new Object();
private Singleton()
{
}
public static Singleton GetInstance()
{
if (instance == null)
{
synchronized (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
进行两次判断,可以避免多次加锁与解锁操作,同时保证线程安全。
静态初始化(饿汉式单例类)
在自己被加载时就将自己实例化
class Singleton
{
private static Singleton instance=new Singleton();
private Singleton()
{
}
public static Singleton GetInstance()
{
return instance;
}
}class Singleton
{
private static Singleton instance=new Singleton();
private Singleton()
{
}
public static Singleton GetInstance()
{
return instance;
}
}
懒汉模式(原先的单例模式):会面临多线程访问的安全性问题,需要做双重锁定处理才能保证安全
饿汉模式(静态初始化方式):是类一加载就实例化的对象,所以要提前占用系统资源
练习
场景问题(读取配置文件到内存)
paramA=a
paramB=b
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class Text {
public static void main(String[] args) {
// TODO Auto-generated method stub
AppConfig config=new AppConfig();
String paramA=config.getParameterA();
String paramB=config.getParameterB();
System.out.println("paramA="+paramA+"paramB="+paramB);
}
}
class AppConfig
{
private String parameterA;
private String parameterB;
public String getParameterA()
{
return parameterA;
}
public String getParameterB()
{
return parameterB;
}
public AppConfig()
{
readConfig();
}
private void readConfig()
{
Properties p=new Properties();
InputStream in=null;
try
{
in=AppConfig.class.getResourceAsStream("AppConfig.properties"); //文件名为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();
}
}
}
}
问题:在系统运行时,系统会存在很多个AppConfig的实例对象,若配置文件较大,将是对资源很大的浪费
懒汉模式
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class Text {
public static void main(String[] args) {
// TODO Auto-generated method stub
AppConfig config=AppConfig.GetAppConfig();
String paramA=config.getParameterA();
String paramB=config.getParameterB();
System.out.println("paramA="+paramA+"paramB="+paramB);
}
}
class AppConfig
{
private String parameterA;
private String parameterB;
private static AppConfig ac; //创建一个私有静态成员
private AppConfig() //将构造方法改为私有
{
readConfig();
}
public String getParameterA()
{
return parameterA;
}
public String getParameterB()
{
return parameterB;
}
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.printStackTrace();
}
}
}
private static final Object syncRoot = new Object();
public static AppConfig GetAppConfig() //创建静态GetAppConfig()方法,双重锁定处理
{
if(ac==null)
{
synchronized(syncRoot)
{
if(ac==null)
{
ac=new AppConfig();
}
}
}
return ac;
}
}
饿汉模式
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class Text {
public static void main(String[] args) {
// TODO Auto-generated method stub
AppConfig config=AppConfig.GetAppConfig();
String paramA=config.getParameterA();
String paramB=config.getParameterB();
System.out.println("paramA="+paramA+"paramB="+paramB);
}
}
class AppConfig
{
private String parameterA;
private String parameterB;
private static AppConfig ac=new AppConfig(); //静态初始化
private AppConfig() //将构造方法改为私有
{
readConfig();
}
public String getParameterA()
{
return parameterA;
}
public String getParameterB()
{
return parameterB;
}
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.printStackTrace();
}
}
}
public static AppConfig GetAppConfig() //创建静态GetAppConfig()方法,双重锁定处理
{
return ac;
}
}