java单例设计模式的区别_Java中几种常见的设计模式--单例设计模式

本文详细介绍了Java中的单例设计模式,包括其定义、适用场景、特点、优缺点及三种实现方式:饿汉模式、懒汉模式(及其线程安全问题与改进)和内部静态类。通过对各种实现方式的比较,展示了如何在保证线程安全的同时提升执行效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、什么是单例设计模式

单例设计模式的定义是只有一个类,并且提供一个全局访问点。

二、适用于那些场景

一个对象即可完成所有工作,无需大量创建对象消耗资源。比如一个长连接,建立起来就不断的发送数据,如果每一个请求都创建一个链接,资源很快就被消耗殆尽。

三、有什么特点

只有一个实例

自我实例化

提供一个全局访问点

四、单例模式的优缺点

优点:由于单例模式只生成了一个实例,所以能够节约系统资源,减少性能开销,提高系统效率,同时也能够严格控制客户对它的访问。

缺点:也正是因为系统中只有一个实例,这样就导致了单例类的职责过重,违背了“单一职责原则”,同时也没有抽象类,这样扩展起来有一定的困难

五、如何创建

方法一 饿汉模式

使用静态常量,在单例类加载的时候就创建了,常见代码如下:

classSingleton1 {//类内部创建实例

private static Singleton1 instance=newSingleton1();//构造方法私有化,防止通过new方式 创建私立

privateSingleton1(){}//对外提供全局同用的唯一调用方法

public staticSingleton1 getInstance(){returninstance;

}

}

这种方式优点缺点都很明显,

优点:类加载的时候实例化,防止对线程同时访问问题。

缺点:类加载时候就实例化,如果没有使用就会造成内存空间的浪费。

方法二懒汉模式

为了解决饿汉模式对于不使用造成内存空间浪费的缺点,又有人提出了懒汉模式,懒汉模式就是在使用时才创建实例,如果不使用就不会创建。

public classSingleton2 {//先声明句柄,但不立即创建实例

private staticSingleton2 instance;//构造方法私有化,防止外部通过使用new方式创建实例

privateSingleton2(){}//想外部提供全局共享的唯一实例化接口方法

public staticSingleton2 getInstance(){if(instance==null){

instance=newSingleton2();

}returninstance;

}

}

但这种懒汉模式也存在一个很大的问题,它有多线程问题,在多个线程同时访问的时候并不能保证单例,我们使用多线程去获取单例,发现获取的实例并不唯一。

public classmytest {public static voidmain(String[] args){long l1=System.currentTimeMillis();

ExecutorService es=Executors.newFixedThreadPool(10);for(int i=0;i<10;i++){

es.execute(newRunnable(){

@Overridepublic voidrun(){

Singleton2 s2=Singleton2.getInstance();

System.out.println(s2);

}

});

}

es.shutdown();while(!es.isTerminated()){}long l2=System.currentTimeMillis();

System.out.println(l2-l1);

}

}

zc.com.examp.test1.core.Singleton2@1ffffbce

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@1ffffbce

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@49ce13ed

5

这是因为在执行instance==null语句时,此时还没有创建实例,此时满足条件的线程都进入,执行instance=new Singleton2()语句。对于此问题,我们可以使用synchronized关键字,让getInstance()方法只能同时被一个线程访问。

public classSingleton2 {//先声明句柄,但不立即创建实例

private staticSingleton2 instance;//构造方法私有化,防止外部通过使用new方式创建实例

privateSingleton2(){}//想外部提供全局共享的唯一实例化接口方法

public static synchronizedSingleton2 getInstance(){if(instance==null){

instance=newSingleton2();

}returninstance;

}

}

测试结果如下:

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@49ce13ed

zc.com.examp.test1.core.Singleton2@49ce13ed

9

可以看到通过使用Synchronized关键字确实可以解决多线程同时访问的问题,但同时也降低了执行效率,每次调用getInstance()方法都要涉及锁的操作。其实我们可以对上面的代码进一步优化。

public classSingleton2 {//先声明句柄,但不立即创建实例

private staticSingleton2 instance;//构造方法私有化,防止外部通过使用new方式创建实例

privateSingleton2(){}//想外部提供全局共享的唯一实例化接口方法

public staticSingleton2 getInstance(){if(instance==null){//只有在第一次使用的时候构造实例对象,使用synchronized代码块和双重判断避免多线程问题,并且提供效率

synchronized(Singleton2.class){if(instance==null){

instance=newSingleton2();

}

}

}returninstance;

}

}

测试结果:

zc.com.examp.test1.core.Singleton2@4c75281a

zc.com.examp.test1.core.Singleton2@4c75281a

zc.com.examp.test1.core.Singleton2@4c75281a

zc.com.examp.test1.core.Singleton2@4c75281a

zc.com.examp.test1.core.Singleton2@4c75281a

zc.com.examp.test1.core.Singleton2@4c75281a

zc.com.examp.test1.core.Singleton2@4c75281a

zc.com.examp.test1.core.Singleton2@4c75281a

zc.com.examp.test1.core.Singleton2@4c75281a

zc.com.examp.test1.core.Singleton2@4c75281a

5

这种方式不仅解决了线程不安全问题,又提升了执行效率,只有前面的少数线程可能会获取锁,只要实例被创建,后面的线程一般只需第一个if判断就返回了对象,所以这种方式推荐使用。

方法三内部静态类。

我们知道饿汉模式缺点就是类在加载时候就创建了实例,容易造成内存资源的浪费,如果在单例类中再创建一个静态内部类,外部类装载的时候静态内部类不会装载,只有使用的时候才会装载,因此达成了懒汉式的效果,实现代码如下:

classSingleton3 {//构造方法私有化,防止通过new方式 创建私立

privateSingleton3(){}//静态内部类,在外部类加载的时候不会加载静态内部类

private static classSingletonInstance{static Singleton3 instance=newSingleton3();

}//对外提供全局同用的唯一调用方法

public staticSingleton3 getInstance(){//只有在使用到静态内部类的时候才会加载,并且通过类加载机制保证在初始化的时候只有一个实例产生

returnSingletonInstance.instance;

}

}

-----------------------------------------------------------------------------------------------------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值