目录
一.单例模式的概念
二.单例模式介绍
三.代码实例
1.饿汉式单例和懒汉式单例
1.1饿汉式单例:
1.2懒汉式单例:
2.如何使懒汉式单例实现线程安全
2.1 synchronized方法
2.2 synchronized块
2.3 双检锁/双重校验锁(DCL,即 double-checked locking)
2.4 登记式/静态内部类的方法
2.5 ThreadLocal方法
3.枚举的方法实现单例模式(666)
四.利用hashcode验证线程安全
注:两种经典单例方法都是实例化一个对象并交给自己的引用,只是创建时机不同。
// 饿汉式单例
public class Singleton1 {
// 私有的构造方法
private Singleton1(){}
// 指向自己实例的私有静态引用,主动创建(饿汉式)
private static Singleton1 singleton1 = new Singleton1();
// 以自己实例为返回值的静态公有方法,静态工厂方法
public static Singleton1 getSingleton1() {
return singleton1;
}
}
//懒汉式单例
public class Singleton2 {
// 私有的构造方法
private Singleton2(){}
// 指向自己实例的私有静态引用,不主动创建实例
private static Singleton2 singleton2 = null;
// 以自己实例为返回值的静态公有方法,静态工厂方法
public static Singleton2 getSingleton2() {
// 被动创建,在真正需要时才创建实例
if(singleton2 == null) {
singleton2 = new Singleton2();
}
return singleton2;
}
}
访问懒汉式单例方式(其余类型访问方式类似):
Singleton2 singleton2 = Singleton2.getSingleton2();
对比饿汉式和懒汉式,不难发现:在多线程环境下,饿汉式是天生线程安全的,因为饿汉式单例在类被加载时,就应经实例化了一个对象并交给自己的引用 ,因为类在整个生命周期只会加载一次,所以单例类只会创建一个实例,线程每次也只会访问这一个实例,所以饿汉式单例是线程安全的。但是饿汉式没有达到Lazy Loading的效果,会造成资源浪费。
懒汉式在多线程情况下并不可用,因为它不是线程安全的:如果有多个线程想实例singleton,当线程1通过了if(singleton == null),但还未执行singleton = new Singleton(),而此时,线程2进入了if(singleton == null),由于此时singleton的状态还是null,所以线程2也通过了判断,此时两个线程就会实例化两个Singleton对象,产生了线程安全问题。
//同步延迟加载 — synchronized方法
public class Singleton3 {
private static Singleton3 singleton3 = null;
private Singleton3(){}
// synchronized关键字,临界资源的同步互斥访问
public static synchronized Singleton3 getSingleton3() {
if(singleton3 == null) {
singleton3 = new Singleton3();
}
return singleton3;
}
}
使用synchronized线程安全的使用方式:
//使用synchronized块实现懒汉式单例;
//安全的方式
public class Singleton4 {
private static Singleton4 singleton4 = null;
private Singleton4(){}
public static Singleton4 getSingleton4() {
// synchronized块,临界资源的同步互斥访问
synchronized (Singleton4.class) {
if(singleton4 == null) {
singleton4 = new Singleton4();
}
}
return singleton4;
}
}
使用sunnchronized线程不安全的使用方式:
// 使用synchronized块实现懒汉式单例;
// 不安全的方式
public class Singleton6 {
private static Singleton6 singleton6 = null;
private Singleton6(){}
public static Singleton6 getSingleton6() {
//线程不安全,原因类似Singleton3
if(singleton6 == null) {
synchronized (Singleton6.class)
{
singleton6 = new Singleton6();
}
}
return singleton6;
}
}
// 双检锁/双重校验锁(DCL,即 double-checked locking)
public class Singleton5 {
private volatile static Singleton5 singleton5 = null;
private Singleton5(){}
public static Singleton5 getSingleton5() {
// DCL
if(singleton5 == null) {
synchronized (Singleton5.class) {
//只需要在第一次创建实例时才同步,提高了效率
if(singleton5 == null) {
singleton5 = new Singleton5();
}
}
}
return singleton5;
}
}
//登记式/静态内部类的方法
public class Singleton7 {
private Singleton7(){}
//私有内部类,按需加载,实现延迟加载
private static class SingletonHolder {
private static Singleton7 singleton7 = new Singleton7();
}
public static Singleton7 getSingleton7() {
return SingletonHolder.singleton7;
}
}
//枚举(666)
public enum Singleton8 {
INSTANCE;
public void whateverMethod() {
}
}
谢谢观看,嘿嘿!
参考博客:
枚举实现单例模式 - SegmentFault 思否
Java设计模式—单例设计模式(Singleton Pattern)完全解析_dmk877的专栏-CSDN博客_单例设计模式java单例模式_czqqqqq的博客-CSDN博客_单例