很多时候我们需要内存中只存在一个类的一个对象,即对象的唯一性。比如,当多线程运行时,需要读取某个文件的内容进行加载并运行,如果这个文件对象不唯一,有可能会重复加载某个类或者功能,造成多条代码执行共享数据(其实这个文件对象就是共享数据了)的线程安全问题,使程序发生错误,这样的情况使我们只想要一个文件对象即可。于是我们就有了单例设计模式。其解决的问题便是
保证一个类在内存中的对象唯一性。
需要对象的唯一性,解决
思路:
1、不能随便让其他程序或是类创建本类对象;
2、可以在本类中创建一个对象,并创建一个对外提供对象的方法,以便让其他程序获得此唯一对象。
步骤:
1、私有化构造函数,那其他程序便不能创建本类对象;
2、在本类中创建一个对象,为保证唯一,私有并静态;
3、创建一个公共的返回本类对象的静态方法。
于是有两种形式可以满足:
饿汉式:
懒汉式:(也称延迟加载形式)
class Single{
private Single(){} //私有化构造函数。
private static Single s = new Single(); //创建私有并静态的本类对象。
public static Single getInstance(){ //定义公有并静态的方法,返回该对象。
return s;
}
}
Class Single2{
private Single2(){}
private static Single2 s = null;
public static Single2 getInstance(){
if(s==null)
s = new Single2();
return s;
}
}
饿汉式一口气将对象创建并私有,在公共方法中该对象返回即可。
懒汉式在对象被需要时,才被创建。
当单例设计模式加入多线程技术时,再看两种模式有什么不同呢?
饿汉式:执行返回对象时,只有一条代码,没有多条代码执行共享数据,不会产生线程安全问题。
懒汉式:
Class Single2{
private Single2(){}
private static Single2 s = null;
public static Single2 getInstance(){
if(s==null) //当线程0进入此处时,cpu切换到另外另外的线程1,则就会产生不只一个对象。问题便产生了
s = new Single2();
return s;
}
}
经过以上的分析,我们知道懒汉式是会产生线程安全问题的,因而,需要进行同步加锁。
class Single2{
private static Single2 s = null;
private Single2(){}
public static synchronized Single2 getInstance(){
if (s == null){
s = new Single2();
}
return s;
}
}
经过上面的同步,便可解决线程安全问题,但还有些小瑕疵。当多线程执行时,不管是否对象已经创建,每条线程都要判断同步锁,会造成效率的降低。是否还有办法呢?试试换成同步代码块的形式。
class Single2{
private static Single2 s = null;
private Single2(){}
public static Single2 getInstance(){
synchronized(Single2.class){
if (s == null){
s = new Single2();
}
}
return s;
}
}
问题依然,每次还是都要判断同步锁。但我们知道,只要创建了对象,其他线程便不能再创建,因而,可以把对象是否为null的条件,做提前判断。
class Single{
private static Single s = null;
private Single(){}
public static Single getInstance(){
if (s == null){ //此判断为提高效率。
synchronized(Single.class){
if (s == null){
s = new Single();
}
}
}
return s;
}
}
这样便能解决效率问题,同步也解决了线程安全问题。