本文介绍了单例模式的六种写法:
-
饿汉式
-
懒汉式(线程不安全)
-
懒汉式(上锁,线程安全)
-
懒汉式(双重校验锁,线程安全)
-
静态内部类(线程安全)
-
枚举(线程安全)
talk is cheap,show you the code:
饿汉式
package com.cc.singleton;
/**
* 单例模式:饿汉式
* 优点:类加载时就实例化完成,线程安全
* 缺点:可能永远都不会被执行到,造成资源浪费
* @author cc
* @date 2021-12-14 15:30
*/
public class Singleton01 {
private static final Singleton01 INSTANCE = new Singleton01();
private Singleton01() {}
public static Singleton01 getInstance() {
return INSTANCE;
}
public static void main(String[] args) {
// 模拟多线程环境下对单例的访问,一个合格的单例应该能保证hashCode()是一致的
for (int i = 0; i < 100; i++) {
new Thread(()-> {
System.out.println(Singleton01.getInstance().hashCode());
}).start();
}
}
}
复制代码
懒汉式(线程不安全)
package com.cc.singleton;
/**
* 单例模式:懒汉式(线程不安全)
* 优点:调用时才进行实例化,资源利用率高
* 缺点:线程不安全
* @author cc
* @date 2021-12-14 15:30
*/
public class Singleton02 {
private static Singleton02 INSTANCE;
private Singleton02() {}
public static Singleton02 getInstance() {
if (INSTANCE == null) {
// 这里模拟实例化耗时来演示懒汉式单例线程不安全
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Singleton02();
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()-> {
System.out.println(Singleton02.getInstance().hashCode());
}).start();
}
}
}
复制代码
懒汉式(上锁,线程安全)
package com.cc.singleton;
/**
* 单例模式:懒汉式(上锁,线程安全)
* 优点:调用时才进行实例化,资源利用率高
* 缺点:每次调用都要上锁,影响性能
* @author cc
* @date 2021-12-14 15:30
*/
public class Singleton03 {
private static Singleton03 INSTANCE;
private Singleton03() {}
public static synchronized Singleton03 getInstance() {
if (INSTANCE == null) {
// 这里模拟实例化耗时
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Singleton03();
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()-> {
System.out.println(Singleton03.getInstance().hashCode());
}).start();
}
}
}
复制代码
懒汉式(双重校验锁,线程安全)
package com.cc.singleton;
/**
* 单例模式:懒汉式(双重校验锁,线程安全)
* 优点:调用时才进行实例化,资源利用率高
* @author cc
* @date 2021-12-14 15:30
*/
public class Singleton04 {
// valatile共享锁可以保证类属性对所有线程可见
private static volatile Singleton04 INSTANCE;
private Singleton04() {}
public static Singleton04 getInstance() {
/**
* 双重校验锁
* 第一次校验不加锁,第二次校验加锁
* 这样单例只会在实例化的时候上锁,实例化后就不会了
*/
if (INSTANCE == null) {
// 这里模拟实例化耗时
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (Singleton04.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton04();
}
}
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()-> {
System.out.println(Singleton04.getInstance().hashCode());
}).start();
}
}
}
复制代码
静态内部类(线程安全)
package com.cc.singleton;
/**
* 单例模式:静态内部类(线程安全)
* 优点:既能保证懒加载,又能保证线程安全
* 这种写法使用JVM的机制保证了线程安全问题
* @author cc
* @date 2021-12-14 15:30
*/
public class Singleton05 {
private static class Singleton05Holder {
private static final Singleton05 INSTANCE = new Singleton05();
}
private Singleton05() {}
public static final Singleton05 getInstance() {
return Singleton05Holder.INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()-> {
System.out.println(Singleton05.getInstance().hashCode());
}).start();
}
}
}
复制代码
枚举(线程安全)
package com.cc.singleton;
/**
* 单例模式:枚举(线程安全)
* 优点:写法优雅,线程安全,还能防止反序列化
* @author cc
* @date 2021-12-14 15:30
*/
public enum Singleton06 {
INSTANCE;
public static Singleton06 getInstance() {
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()-> {
System.out.println(Singleton06.getInstance().hashCode());
}).start();
}
}
}
复制代码