目录
1. 基本定义
2. 饿汉式
3. 懒汉式
4. 静态内部类单例
1. 基本定义
单例模式就是确保某一个类只有一个实例,并且提供一个全局访问点。
单例模式特点:
- 构造方法私有化
- 实例化的变量引用私有化
- 获取实例的方法共有
2. 饿汉式
不管用不用的上,一开始就建立单例对象
/**
* 饿汉式
* 类一旦加载进内存,就实例化一个单例,JVM保证线程安全
* 简单实用
* 唯一缺点: 不管用到与否,类一旦加载就完成实例化
*/
public class Singleton {
// 实例变量引用私有化
private static final Singleton singleton = new Singleton();
// 构造方法私有化
private Singleton(){
}
// 获取实例的方法共有
public Singleton getSingleton(){
return singleton;
}
}
3. 懒汉式
“懒汉式”是真正用到的时候才去建这个单例对象
线程不安全的懒汉式
/**
* lazy loading
* 懒汉式
* 虽然达到了按需初始化的目的,但却带来线程不安全的问题
*/
public class Singleton1 {
private static Singleton1 singleton;
private Singleton1(){
}
private static Singleton1 getSingleton(){
if(singleton == null) {
singleton = new Singleton1();
}
return singleton;
}
}
通过加synchronized锁保证线程安全的懒汉式
/**
* 懒汉式
*/
public class Singleton2 {
private static Singleton2 singleton2;
private Singleton2(){}
// 锁的是当前类的class对象,加锁效率会低
public static synchronized Singleton2 getSingleton2(){
if(singleton2 == null) {
singleton2 = new Singleton2();
}
return singleton2;
}
}
通过双重校验锁来保证线程安全的懒汉式
注意volatile关键字,原因参考我的另一篇文章,主要是防止指令重排问题:传送门
也可以参考这个: 链接
/**
* 双重校验锁保证线程安全的单例模式
*/
public class Singleton3 {
// 注意要加volatile关键字才能保证线程安全
private static volatile Singleton3 singleton3;
private Singleton3(){
}
public Singleton3 getSingleton3(){
if(singleton3 == null) {
synchronized (Singleton3.class) {
// 再次判断
if(singleton3 == null) {
singleton3 = new Singleton3();
}
}
}
return singleton3;
}
}
4. 静态内部类单例
利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗
public class Singleton4 {
private Singleton4(){
}
// 静态内部类JVM保证单例
private static class Singleton4Holder{
private final static Singleton4 singleton4 = new Singleton4();
}
public Singleton4 getSingleton4(){
return Singleton4Holder.singleton4;
}
}
测试
public static void main(String[] args) {
Singleton4 singleton4 = new Singleton4();
for (int i = 0; i < 5; i++) {
new Thread(() -> {
System.out.println(singleton4.getSingleton4().hashCode());
}).start();
}
}