一 饿汉式
- 类加载到内存后,只能在内存中有一个实例,JVM保证线程安全
- 缺点:不管是否用到,类加载时就会实例化
public class Singleton {
private static final Singleton INSTANCE=new Singleton();
//私有构造方法
private Singleton(){
}
public static Singleton getInstance(){
return INSTANCE;
}
}
二 懒汉式(线程不安全版)
- 调用getInstance()方法的时候才会创建实例,线程不安全
public class Singleton2 {
private static Singleton2 INSTANCE;
private Singleton2(){
}
public static Singleton2 getInstance(){
if(INSTANCE == null){
try {
//多线程状态下,可能有多个线程同时走到这里,会导致创建多个实例
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Singleton2();
}
return INSTANCE;
}
public static void main(String[] args) {
//创建100个线程,看每个线程获取到的实例是否相同,不通实例hashcode不一样
for(int i=0;i<100;i++){
new Thread(()-> System.out.println(Singleton2.getInstance().hashCode())).start();
}
}
}
三 懒汉式(线程安全版)
- 对getInstance()方法加锁(静态方法加锁实际锁的是Singleton2.class类对象)
- 线程安全但是会导致效率变低
public static synchronized Singleton2 getInstance(){
//内容同二
}
打印结果可以看到hashcode是同一个,说明线程安全
四 懒汉式(减小锁粒度版)
- 通过减小锁代码块,来提高性能。但是仍然会导致线程不安全问题
public class Singleton3 {
private static Singleton3 INSTANCE;
private Singleton3() {
}
public static Singleton3 getInstance() {
if (INSTANCE == null) {
//当多个线程同时走到这里,还是会导致创建多个实例
synchronized (Singleton3.class) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Singleton3();
}
}
return INSTANCE;
}
public static void main(String[] args) {
for(int i=0; i<100; i++) {
new Thread(()-> System.out.println(Singleton3.getInstance().hashCode())).start();
}
}
}
五 懒汉式(双重检查线程安全版)
- 线程安全又减小了同步代码块
public class Singleton4 {
private static volatile Singleton4 INSTANCE;
private Singleton4(){
}
public static Singleton4 getInstance(){
if(INSTANCE == null){
//即使多个线程同时走到了这里,只有一个线程先执行以下同步代码块
synchronized (Singleton4.class){
//当第二个线程走到这里,实例已经初始化将不会再次执行以下if代码块
if(INSTANCE == null){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE=new Singleton4();
}
}
}
return INSTANCE;
}
public static void main(String[] args) {
for(int i=0;i<100;i++){
new Thread(()-> System.out.println(Singleton4.getInstance().hashCode())).start();
}
}
}
六 枚举版(线程安全)
public enum Singleton5 {
INSTANCE;
public static void main(String[] args) {
for(int i=0;i<100;i++){
new Thread(()-> System.out.println(Singleton5.INSTANCE.hashCode())).start();
}
}
}