设计模式之单例设计模式的5种不同实现方式
1.饿汉式
类加载到内存后,就实例化一个单例,JVM保证线程安全,唯一缺点:不管用到与否,类装载时就完成实例化。简单实用,推荐使用!
public class Sin01 {
private static final Sin01 INSTANCE=new Sin01();
private Sin01(){}
public static Sin01 getInstance(){
return INSTANCE;
}
public static void main(String[] args) {
Sin01 m1 = Sin01.getInstance();
Sin01 m2 = Sin01.getInstance();
System.out.println(m1 == m2);
}
}
2.跟1是一个意思,但是是在静态代码块中实现
public class Sin02 {
private static final Sin02 INSTANCE;
static {
INSTANCE = new Sin02();
}
private Sin02() {};
public static Sin02 getInstance() {
return INSTANCE;
}
public static void main(String[] args) {
Sin02 m1 = Sin02.getInstance();
Sin02 m2 = Sin02.getInstance();
System.out.println(m1 == m2);
}
}
3.懒汉式
虽然达到了按需初始化的目的,但多线程访问时却带来线程不安全的问题,但可以通过synchronized解决,但也带来效率下降
public class Sin04 {
private static Sin04 INSTANCE;
private Sin04() {
}
public static synchronized Sin04 getInstance() {
if (INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Sin04();
}
return INSTANCE;
}
public static void main(String[] args) {
for(int i=0; i<100; i++) {
new Thread(()->{
System.out.println(Sin04.getInstance().hashCode());
}).start();
}
}
}
4.懒汉式-双重检查方法
public class Sin06 {
private static volatile Sin06 INSTANCE;
private Sin06() {
}
public static Sin06 getInstance() {
if (INSTANCE == null) {
//双重检查
synchronized (Sin06.class) {
if(INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Sin06();
}
}
}
return INSTANCE;
}
public static void main(String[] args) {
for(int i=0; i<100; i++) {
new Thread(()->{
System.out.println(Sin06.getInstance().hashCode());
}).start();
}
}
}
5.完美的方式
静态内部类方式,JVM保证单例且保证线程安全,加载外部类时不会加载内部类,这样可以实现懒加载
public class Sin07 {
private Sin07() {
}
private static class Mgr07Holder {
private final static Sin07 INSTANCE = new Sin07();
}
public static Sin07 getInstance() {
return Mgr07Holder.INSTANCE;
}
public static void main(String[] args) {
for(int i=0; i<100; i++) {
new Thread(()->{
System.out.println(Sin07.getInstance().hashCode());
}).start();
}
}
}
6.枚举单例-完美中的完美方式
不仅可以解决线程同步,还可以防止反序列化。
public enum Sin08 {
INSTANCE;
public static void main(String[] args) {
for(int i=0; i<100; i++) {
new Thread(()->{
System.out.println(Sin08.INSTANCE.hashCode());
}).start();
}
}
}
推荐使用的是1和5的方式