SINGLEPATTERN
单例模式定义:
Ensure a class has only one instance, and provide a global point of access to it.(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。)
单例类(懒汉式)
package singletonpattern;
public class Singleton {
private static Singleton st = null;
private Singleton() {}
public static Singleton getinstance() {
if(st==null) {
st = new Singleton();
}
return st;
}
}
单例类(饿汉式)
package singletonpattern;
public class Singleton {
private static Singleton st = new Singleton();
private Singleton() {}
public static Singleton getinstance() {
return st;
}
}
静态内部类
package singletonpattern;
public class Singleton {
private Singleton() {}
public static Singleton getinstance() {
return Sinsta.st;
}
private static class Sinsta {
private static Singleton st = new Singleton();
}
}
静态内部枚举类
package singletonpattern;
public class Singleton {
private Singleton() {}
public static Singleton getinstance() {
return EnumSingle.INSTANCE.getSingleton();
}
private static enum EnumSingle {
INSTANCE;
private Singleton st;
private EnumSingle() {
st = new Singleton();
}
private Singleton getSingleton() {
return st;
}
}
}
测试类
public class Test {
public static void main(String[] args) {
System.out.println(Singleton.getinstance().hashCode());
System.out.println(Singleton.getinstance().hashCode());
}
}
输出结果一致为:
2018699554
2018699554
多线程测试类
package singletonpattern;
public class TestThread extends Thread {
@Override
public void run() {
System.out.println(Singleton.getinstance().hashCode());
}
public static void main(String[] args) {
TestThread[] tts = new TestThread[10];
for(int i = 0 ; i < tts.length ; i++){
tts[i] = new TestThread();
}
for (int j = 0; j < tts.length; j++) {
tts[j].start();
}
}
}
静态内部枚举类型在多线程测试下输出为
1228857876
1228857876
1228857876
1228857876
1228857876
1228857876
1228857876
1228857876
1228857876
1228857876
结果一致,线程安全
静态内部类在多线程测试下输出为
1501822625
1501822625
1501822625
1501822625
1501822625
1501822625
1501822625
1501822625
1501822625
1501822625
结果一致,线程安全
饿汉式在多线程测试下输出为
1228857876
1228857876
1228857876
1228857876
1228857876
1228857876
1228857876
1228857876
1228857876
1228857876
结果一致,线程安全
懒汉式在多线程测试下输出为
1228857876
621856954
621856954
621856954
621856954
621856954
621856954
621856954
621856954
621856954
结果不一致,线程不安全
那么怎么让懒汉式单例模式是线程安全的呢
在获取对象的方法上添加
synchronized
关键字,是方法变为同步方法代码示例:
public static synchronized Singleton getinstance() { if(st==null) { st = new Singleton(); } return st; }
在获取对象的方法里添加同步代码块
代码示例:
public static Singleton getinstance() { synchronized(Singleton.class) { if(st==null) { st = new Singleton(); } } return st; }
在获取对象的方法里进行双重检查添加同步代码块
代码示例:
private volatile static Singleton st = null; public static Singleton getinstance() { if(st==null) { synchronized(Singleton.class) { if(st==null) { st = new Singleton(); } } } return st; }
为什么静态内部枚举的单例就是线程安全的?
枚举enum和静态代码块的特性相似,在使用枚举时,构造方法会被自动调用
为什么静态内部类的单例就是线程安全的?
静态属性-静态代码块-非静态属性-构造方法,这是总体加载顺序,其中静态属性静态代码块在声明的时候开始调用且只加载一次,而静态内部类在调用时才会加载而且也只加载一次,所以JVM从主线程即底层保证了静态内部类里边的对象只会有一个。