singleton (单例)
1. 饿汉式
/**
* 饿汉式
* 类加载到内存后,就实例化一个单例,JVM保证线程安全
* 简单实用
*/
public class Singleton01 {
private static final Singleton01 singleton = new Singleton01();
private Singleton01() {
}
public static Singleton01 getInstance() {
return singleton;
}
}
如果一个类中的成员属性比较少,且占用的内存资源不多,可以使用饿汉式
如果类中成员都是比较重的资源,那这种方式就会有些不妥
2. 懒汉式
/**
* 懒汉式
* 虽然达到了按需初始化的目的,但是带来了多线程访问不安全的问题
* 当多个线程同时进到if判断里,会多次被创建
*/
public class Singleton02 {
private static Singleton02 singleton;
private Singleton02() {
}
public static Singleton02 getInstance() {
if (singleton == null) {
singleton = new Singleton02();
}
return singleton;
}
}
3. 懒汉式增强(Double-Check)
/**
* 采用懒汉式+数据同步的方式
* 满足了懒加载与实例的唯一性
* 但是synchronized排他性导致性能低下
*/
public class Singleton04 {
//考虑为什么要加volatile?美团面试题,DCL单例是否有必要加volatile?
private static volatile Singleton04 singleton;
private Socket socket;
private Singleton04() {
//进行socket实例化
}
public static Singleton04 getInstance() {
if (singleton == null) {
synchronized (Singleton04.class) {
if (singleton == null) {
singleton = new Singleton04();
}
}
}
return singleton;
}
}
4. 静态内部类
/**
* 静态内部类
* jvm保证单例
* 加载外部类不会加载内部类,这样可以实现懒加载
*/
public class Singleton05 {
private Singleton05() {
}
private static class Singleton05Holder {
private static final Singleton05 singleton = new Singleton05();
}
public static Singleton05 getInstance() {
return Singleton05Holder.singleton;
}
/**
* 测试代码
*
* @param args
*/
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
Singleton05 singleton02 = Singleton05.getInstance();
System.out.println(singleton02.hashCode());
}).start();
}
}
}
在Singleton05类中并没有该类的实例的静态成员,而是放到静态内部类Holder中,因此Singleton05类的初始化并不会创建该类的实例,只有当Holder被主动引用的时候才会创建Singleton05类的实例,Singleton05实例的创建过程在Java程序编译时期收集至
()方法中,该方法是同步方法,可以保证内存的可见性、JVM指令的顺序性和原子性,所以该方式的单例设计是最好的设计之一,也是目前使用比较广泛的设计之一
5. 完美方式
/**
* effective java 给出的完美方式
* 不仅解决线程同步,还可以防止反序列化
*/
public enum Singleton06 {
INSTANCE;
/**
* 测试代码
*
* @param args
*/
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
Singleton06 singleton02 = Singleton06.INSTANCE;
System.out.println(singleton02.hashCode());
}).start();
}
}
}