概念
- 创建型模式
- 通过单例模式的方法创建的类在当前进程中只有一个
场景
单例细分
sequenceDiagram
问->>答: 最简单的?
答-->>问: 01、饿汉式———线程安全
问-)答: 类太多,服务启动太慢怎么办?
答-->>问: 02、懒汉式——线程不安全
问-)答: 这个线程不安全?
答-->>问: 03、懒汉式——线程安全(同步)
问-)答: 方法使用sychronized,影响性能?
答-->>问: 04、懒汉式——线程安全(双重锁校验)
问-)答: 使用JUC能实现吗?
答-->>问: 05、懒汉式——线程安全(CAS高并发)
问-)答: 无锁化能吗?
答-->>问: 06、懒汉式——线程安全(内部类)
问-)答: 枚举类能搞吗?
答-->>问: 07、枚举式——线程安全
01、饿汉式———线程安全
- 程序启动,实例化对象
- 类多会导致启动缓慢
- 可能某些类,只需在使用时实例化
public class HungrySafe{
private static final HungrySafe hungrySafe=new HungrySafe();
private static final HungrySafe hungrySafe;
static{
hungrySafe=new HungrySafe();
}
public static HungrySafe getInstance(){
return hungrySafe;
}
}
public class HungrySafeTest {
public static void main(String[] args) {
HungrySafe map=HungrySafe.getInstance();
HungrySafe map2=HungrySafe.getInstance();
System.out.println(map);
System.out.println(map2);
}
}
02、懒汉式(线程不安全)
- 构造函数私有化
- 第一次使用时,创建实例
- 多线程会产生多实例(不安全)
public class LazyUnSafe {
private static LazyUnSafe lazyUnSafe;
private LazyUnSafe(){ }
public static LazyUnSafe getInstance(){
if(lazyUnSafe!=null){
return lazyUnSafe;
}
lazyUnSafe= new LazyUnSafe();
return lazyUnSafe;
}
}
class LazyUnSafeTest {
public static void main(String[] args) throws InterruptedException {
Thread t=new Thread(()->{
LazyUnSafe lazyUnSafe=LazyUnSafe.getInstance();
System.out.println(lazyUnSafe);
});
t.start();
LazyUnSafe lazyUnSafe=LazyUnSafe.getInstance();
System.out.println(lazyUnSafe);
}
}
03、懒汉式-同步 (线程安全)
- 方法增加synchoronized关键字(同步锁)
- 所有的访问都需要 锁占用(获取/释放锁)
- 不建议使用
public class LazySafeSync {
private static LazySafeSync lazySafeSync=new LazySafeSync();
private LazySafeSync(){}
public static synchronized LazySafeSync getInstance(){
if(lazySafeSync!=null){
return lazySafeSync;
}
return lazySafeSync;
}
}
class LazySafeSyncTest {
public static void main(String[] args) {
Thread t=new Thread(()->{
LazySafeSync lazySafeSync=LazySafeSync.getInstance();
System.out.println(lazySafeSync);
});
t.start();
LazySafeSync lazySafeSync=LazySafeSync.getInstance();
System.out.println(lazySafeSync);
}
}
04、懒汉式-双重锁校验(线程安全)
- synchoronized关键字不使用在方法上
- 对类对象进行加锁
- 性能有所提升(对比03)
public class LazySafeSyncX {
private static volatile LazySafeSyncX lazyUnSafe;
private LazySafeSyncX(){}
public static LazySafeSyncX getInstance(){
if(lazyUnSafe!=null){
return lazyUnSafe;
}
synchronized (LazySafeSync.class){
if(lazyUnSafe==null){
lazyUnSafe=new LazySafeSyncX();
}
}
return lazyUnSafe;
}
}
class LazySafeSyncXTest {
public static void main(String[] args) {
Thread t=new Thread(()->{
LazySafeSyncX lazySafeSyncX=LazySafeSyncX.getInstance();
System.out.println(lazySafeSyncX);
});
t.start();
LazySafeSyncX lazySafeSyncX=LazySafeSyncX.getInstance();
System.out.println(lazySafeSyncX);
}
}
05、懒汉式-CAS(线程安全)
- CAS算法,AtomicReference原子类
- 支持高并发,无线程切换和阻塞
- 竞争激烈会导致一直循环等待-->死循环(CPU性能)
public class LazySafeAtomic {
private static final AtomicReference<LazySafeAtomic> reference=new AtomicReference<>();
private LazySafeAtomic(){ }
public static LazySafeAtomic getInstance(){
for (;;){
LazySafeAtomic lazySafeAtomic=reference.get();
if(lazySafeAtomic!=null){
return lazySafeAtomic;
}
reference.compareAndSet(null,new LazySafeAtomic());
return reference.get();
}
}
}
class LazySafeAtomicTest {
public static void main(String[] args) {
Thread t=new Thread(()->{
LazySafeAtomic lazySafeAtomic=LazySafeAtomic.getInstance();
System.out.println(lazySafeAtomic);
});
t.start();
LazySafeAtomic lazySafeAtomic=LazySafeAtomic.getInstance();
System.out.println(lazySafeAtomic);
}
}
06、懒汉式-内部类(线程安全)
- 静态内部类保证创建唯一实例
- 懒加载,线程安全,无锁化性能高
- 推荐使用
public class LazySafeInner {
private LazySafeInner(){ }
private static class LazySafeInnerHolder{
private static LazySafeInner lazySafeInner=new LazySafeInner();
}
public static LazySafeInner getInstance(){
return LazySafeInnerHolder.lazySafeInner;
}
}
class LazySafeInnerTest {
public static void main(String[] args) {
Thread t=new Thread(()->{
LazySafeInner lazyUnSafe=LazySafeInner.getInstance();
System.out.println(lazyUnSafe);
});
t.start();
LazySafeInner lazyUnSafe=LazySafeInner.getInstance();
System.out.println(lazyUnSafe);
}
}
07、枚举式(线程安全)
- 推荐
- 线程安全、自由串行化、单一实例
- 防止反射
- 不适用继承场景
public enum LazySafeEnum {
INSTANCE;
public void hello(){
System.out.println("hello ");
}
}
class LazySafeEnumTest {
public static void main(String[] args) {
LazySafeEnum.INSTANCE.hello();
}
}