java 单例 销毁_java单例设计模式,这一篇就够了

单例即单个实例,在我们生产活动中有些类没必要好多实例存在的。

单例模式严格来讲有8种写法。

利用类加载器帮助我们实现单例模式。用jvm来保证我们的线程安全。

public class Mgr01{

private static final Mgr01 INSTANCE=new Mgr01();

private Mgr01();

Public static Mgr01 getInstance{return INSTANCE};

Public static void main(String[]args){

Mgr01 m1=Mgr01.getInstance();

Mgr01 m2=Mgr01.getInstance();

System.out.println(m1==m2);

}

唯一缺点,无论是否用到,都会有一个实例。

第一个稍微改造版,给第一个没什么区别。

public class Mgr02{

private static final Mgr02 INSTANCE;

Static{

INSTANCE=new Mgr01();

private Mgr02();

Public static Mgr02 getInstance{return INSTANCE};

Mgr02 m1=Mgr02.getInstance();

Mgr02 m2=Mgr02.getInstance();

懒汉式:达到初始化目的,带来了线程安全问题

public class Mgr03{

private static final Mgr03 INSTANCE;

private Mgr03();

Public static Mgr03 getInstance(){

If(INSTANCE==null){

try{Thread.sleep(1);}catch(Exception e){}

Instance=new Mgr03();

Return Instance;

};

for(int i=0;i<1000;i++){

New Thread(()->{

System.out.println(Mgr03 .getInstance.hashCode());

}).start();

懒汉式进行改进

public class Mgr04{

private static final Mgr04 INSTANCE;

private Mgr04();

Public static synchronized Mgr04 getInstance(){

Instance=new Mgr04();

System.out.println(Mgr04 .getInstance.hashCode());

缺点:这样效率会降低,那有没有办法加锁的同时,效率也提高了。不在整个方法加锁。

public class Mgr05{

private static final Mgr05 INSTANCE;

private Mgr05();

Public static Mgr05 getInstance(){

Synchronized(Mgr05 .class){

Instance=new Mgr05();}

System.out.println(Mgr05 .getInstance.hashCode());

在多线程访问下,不能做到只有一个实例。不能保证判断Instance为空的时候进来两个线程。

双重校验锁:

public class Mgr06{

private static final Mgr06 INSTANCE;

INSTANCE=new Mgr06();

private Mgr06();

Public static Mgr06 getInstance(){

Synchronized(Mgr06 .class){

Instance=new Mgr06();}

System.out.println(Mgr06 .getInstance.hashCode());

静态内部类,jvm保证单实例,加载外部类不会加载内部类,这样可以实现懒加载.

public class Mgr07{

Private Static class Mgr07Holder{

private static final Mgr07 INSTANCE=new Mgr07 ();

private Mgr07();

Public static Mgr07 getInstance(){

Return Mgr07Holder.Instance;

System.out.println(Mgr07 .getInstance.hashCode());

以上可以通过反射创建。

枚举模式创建单例,

public class EnumSingleton {

private EnumSingleton(){}

public static EnumSingleton getInstance(){

return Singleton.INSTANCE.getInstance();

}

private static enum Singleton{

INSTANCE;

private EnumSingleton singleton;

//JVM会保证此方法绝对只调用一次

private Singleton(){

singleton = new EnumSingleton();

}

public EnumSingleton getInstance(){

return singleton;

单例模式只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等。如:

1.需要频繁实例化然后销毁的对象。

2.创建对象时耗时过多或者耗资源过多,但又经常用到的对象。

3.有状态的工具类对象。

4.频繁访问数据库或文件的对象。

以下都是单例模式的经典使用场景:

1.资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。

2.控制资源的情况下,方便资源之间的互相通信。如线程池等。

应用场景举例:

1.外部资源:每台计算机有若干个打印机,但只能有一个PrinterSpooler,以避免两个打印作业同时输出到打印机。内部资源:大多数软件都有一个(或多个)属性文件存放系统配置,这样的系统应该有一个对象管理这些属性文件

2. Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~

3. windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。

4. 网站的计数器,一般也是采用单例模式实现,否则难以同步。

5. 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。

6. Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。

7. 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。

8. 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。

9. 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。

10. HttpApplication 也是单位例的典型应用。熟悉ASP.Net(IIS)的整个请求生命周期的人应该知道HttpApplication也是单例模式,所有的HttpModule都共享一个HttpApplication实例。

89012083869e06b2f0852086bac148e3.png

在spring中

spring的Bean默认的是单例的,Bean的作用域可以通过Bean标签的scope属性进行设置,Bean的作用域包括:

默认情况下scope="singleton",那么该Bean是单例,任何人获取该Bean实例的都为同一个实例;

scope="prototype",任何一个实例都是新的实例;

scope="request",在WEB应用程序中,每一个实例的作用域都为request范围;

scope="session",在WEB应用程序中,每一个实例的作用域都为session范围;

注意:在默认情况下,Bean实例在被Spring容器初始化的时候,就会被实例化,默认调用无参数的构造方法。在其它情况下,Bean将会在获取实例的时候才会被实例化。

在使用log4j框架时也注意到了其使用的是单例,当然也为了保证单个线程对日志文件的读写时不出问题,与使用spring管理bean的目标不是相似,如下为其logfactory单例创建的源码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值