1,饿汉式,也叫立即加载,就是使用类的时候已经将对象创建完毕,常用的方法是直接new实例化。
public class SingletonObject {
private static SingletonObject sObj = new SingletonObject();
private SingletonObject(){
}
public static SingletonObject getInstance(){
return sObj;
}
}
2,懒汉式,也叫延迟加载,就是在调用get()方法时实例才被创建。
测试代码:
public class SingletonObject {
//private static SingletonObject sObj = new SingletonObject();
private static SingletonObject sObj;
public static SingletonObject getInstance(){
try {
if (sObj == null) {
synchronized(SingletonObject.class){
//使用双重检测,因为可能有多个线程同时进入到第一个:if (sObj == null)的代码块中,
//如果这里不再次判断sObj是否为null,在前一个线程退出同步块后,后面的线程拿到锁,也会再次实例化。
if(sObj == null){
//睡眠2秒,模拟耗时操作
Thread.sleep(2000);
sObj = new SingletonObject();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return sObj;
}
}
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("sObj="+SingletonObject.getInstance().hashCode());
}
}
public class RunTest {
public static void main(String[] args) {
int count = 10;
MyThread[] mts = new MyThread[count];
for(int i=0; i<count; i++){
mts[i] = new MyThread();
mts[i].start();
}
}
}
运行结果:
sObj=6842105
sObj=6842105
sObj=6842105
sObj=6842105
sObj=6842105
sObj=6842105
sObj=6842105
sObj=6842105
sObj=6842105
sObj=6842105
public class SingletonObject {
private SingletonObject(){
}
private static class InnerObject{
private static SingletonObject sObj = new SingletonObject();
}
public static SingletonObject getInstance(){
return InnerObject.sObj;
}
}
多数情况下,这种写法都是可以得到预期结果的,实现了线程安全。
4,当静态内部类,遇到序列化和反序列化,得到的还是多实例。测试代码:
public class SingletonObject implements Serializable{
private static SingletonObject sObj;
private SingletonObject(){
}
private static class InnerObject{
private static SingletonObject sObj = new SingletonObject();
}
public static SingletonObject getInstance(){
return InnerObject.sObj;
}
}
public class RunTest {
public static void main(String[] args) {
try{
SingletonObject sObj = SingletonObject.getInstance();
FileOutputStream fosRef = new FileOutputStream(new File("singletonObjFile.txt"));
ObjectOutputStream oosRef = new ObjectOutputStream(fosRef);
oosRef.writeObject(sObj);
oosRef.close();
fosRef.close();
System.out.println("write,sObj="+sObj.hashCode());
}catch(FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try{
FileInputStream fisRef = new FileInputStream(new File("singletonObjFile.txt"));
ObjectInputStream iosRef = new ObjectInputStream(fisRef);
SingletonObject sObj = (SingletonObject)iosRef.readObject();
iosRef.close();
fisRef.close();
System.out.println("read,sObj="+sObj.hashCode());
}catch(FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
运行结果:
write,sObj=6585861
read,sObj=8860464
可以看到,写入的值跟读出的值是不一致的。
解决的办法是在反序列化时调用readResolve()方法。
修改代码:
public class SingletonObject implements Serializable{
private SingletonObject(){
}
private static class InnerObject{
private static SingletonObject sObj = new SingletonObject();
}
public static SingletonObject getInstance(){
System.out.println("call getInstance method.");
return InnerObject.sObj;
}
protected Object readResolve() throws ObjectStreamException{
System.out.println("call readResolve method.");
return InnerObject.sObj;
}
}
运行结果:
call getInstance method.
write,sObj=6585861
call readResolve method.
read,sObj=6585861
5,用静态代码块实现单例。
测试代码:
public class SingletonObject{
private static SingletonObject sObj;
private SingletonObject(){
}
static{
sObj = new SingletonObject();
}
public static SingletonObject getInstance(){
return InnerObject.sObj;
}
}