单例模式的几种创建方式
程序员文章站
2022-07-14 09:25:09
...
1、饿汉式
public class Demo1 {
private static Demo1 instance = new Demo1();
private Demo1(){
}
public static Demo1 newInstance(){
return instance;
}
public static void main(String[] args) {
Demo1 demo1 = Demo1.newInstance();
Demo1 demo2 = Demo1.newInstance();
System.out.println(demo1 == demo2);
}
}
单例模式的构造器都是私有的
这种方式是线程安全的,在类加载的过程中创建;缺点是如果这个类没有被使用过的话,导致资源的浪费
2、懒汉式
public class Demo2 {
private static Demo2 instance = null;
private Demo2(){}
public static Demo2 newIntance(){
if(instance == null){
instance = new Demo2();
}
return instance;
}
public static void main(String[] args) {
Demo2 demo2 = Demo2.newIntance();
Demo2 demo21 = Demo2.newIntance();
System.out.println(demo2 == demo21);
}
}
优点:该模式在需要的时候才创建(懒加载);
缺点:非线程安全的
if(instance == null){
instance = new Demo2();
}
如果线程同时进入这块区域,就会造成Demo2多次创建
3、改进懒汉模式
在newInstance方法上加锁synchronized
这种方式解决了线程安全的问题和懒加载的问题,但是如果这个对象已经创建了,而我以后每次调用都会加锁,影响效率
4、双重锁检模式
public class Demo3 {
private static Demo3 instance = null;
private Demo3(){
}
public static Demo3 newInstance(){
if(instance == null){
synchronized (Demo3.class){
if(instance == null){
instance = new Demo3();
}
}
}
return instance;
}
}
缺点:这个也不是线程安全的,因为会产生指令重排
改进加volatile关键字
public class Demo3 {
private static volatile Demo3 instance = null;
private Demo3(){
}
public static Demo3 newInstance(){
if(instance == null){
synchronized (Demo3.class){
if(instance == null){
instance = new Demo3();
}
}
}
return instance;
}
}
通过双重锁检+volatile ,这样就真正做到了线程安全和懒加载了
5、静态内部类
public class Demo4 {
private Demo4(){}
private static class SDemo4{
private static Demo4 instance = new Demo4();
}
public static Demo4 getInstance(){
return SDemo4.instance;
}
}
在一个类被加载的时候并不会加载其静态内部类,只有当其中的某个静态成员(静态域、构造器、静态方法等)被调用时,才会加载这个内部类;而且类加载的过程是线程安全的。
当然如果通过反射的方式创建该对象,这就不是单例的了
public static void main(String[] args) throws Exception {
Demo4 d1 = Demo4.getInstance();
Class<Demo4> clzz = Demo4.class;
Constructor<Demo4> declaredConstructor = clzz.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Demo4 d2 = declaredConstructor.newInstance();
System.out.println(d1 == d2);//false
}
6、通过枚举创建单例
public enum Demo5 {
INSTANCE;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void doSomeThing(){
System.out.println("hello world");
}
@Override
public String toString() {
return "[" + name + "]";
}
}
public static void main(String[] args) throws Exception {
Demo5.INSTANCE.doSomeThing();
}
推荐使用枚举
上一篇: 工厂方法模式
下一篇: k8s学习()之K8S中遇到的各种问题