什么叫单例模式?
单例模式就是类中只存在唯一一个类对象(例如Runtime)。
1.如下所示,在同一个包下创建两个类,在Test类中创建两个Single()对象。那么此时的Single类就不能叫做单例。
package com.test;
public class Test {
public static void main(String[] args) {
new Single();
new Single();
}
}
package com.test;
public class Single {
}
2.那么为了保证类的唯一性:
- 我们可以私有Single构造方法,在本类的成员位置创建它自己类的对象,然后提供公共方法返回它创建的对象。
- 因为需要Test类创建Single对象,Single私有化后我们又不能直接创建Single对象,所以只能直接调用Single中静态的公共方法区域返回Single对象。
- 又因为静态的不能访问非静态的,所以将Single创建的对象也变成静态的。
package com.test;
//这种模式又被称为单例模式之饿汉模式,指该方法自己先在自己类里面创建一个Single对象,然后供其他类去调用。
public class Single {
private Single(){}
private static final Single s = new Single();//加final是为了更加安全
public static Single getInstance(){
return s;
}
}
package com.test;
public class Test {
public static void main(String[] args) {
for(int i=0; i<20; i++){
Single s = Single.getInstance();
System.out.println(s);
}
}
}
3.单例模式的另一种模式,延迟加载模式。但是这种模式存在弊端,这种模式在多线程并发的情况下会有隐患,当两个线程同时调用Single中的方法时,第二个线程会有可能性判断S为空,那么就会new出第二个对象。
//对象的延迟加载,当有类需要Single对象时,Single才去创建它的对象
public class Single {
private Single(){}
private static Single s = null;
public static Single getInstance(){
if(s == null)
s = new Single();
return s;
}
}
package com.test;
public class Test {
public static void main(String[] args) {
Run r = new Run();
new Thread(r).start();
new Thread(r).start();
}
}
package com.test;
public class Run implements Runnable {
public void run(){
for(int i=0; i<20; i++){
Single s = Single.getInstance();
System.out.println(s);
}
}
}
4.怎么解决这种安全隐患呢?如下所示,我们可以在判断之前加个同步代码块。
//对象的延迟加载
public class Single {
private Single(){}
private static Single s = null;
public static Single getInstance(){
if( s == null){//双重判断是为了提升效率
synchronized(Single.class){//锁是为了提高安全性
if(s == null)
s = new Single();
}
}
return s;
}
}