单例模式分析

分析java中的单例模式的实现、多线程并发、在内存中是否会被GC回收? 在一个系统中,要求一个类有且仅有一个对象,如果出现多个对象就会出现“不良反应”时,则可以采用单例模式,具体的场景如下:

  • 要求生成唯一序列号的环境;
  • 在整个项目中需要有访问一个共享访问点或共享数据,例如一个Web页面上的计数器,可以不用每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;
  • 创建一个对象需要消耗的资源过多,如要访问IO、访问数据库等资源;
  • 需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当然,也可以直接声明为static的方式);
  • 加载常用数据到内存,避免每次调用这部分数据,都要访问数据库


    分析一段代码。场景 在springmMVC项目启动时候,加载部分数据到内存。


<!-- 服务启动,开始加载**数据方案->

    <bean id="testCacheUtil" class="com.hhc.cache.testCacheUtil"
factory-method="getInstance" />


@SuppressWarnings("unchecked")
public class testCacheUtil {
private static final testCacheUtil instance=new testCacheUtil();

private List list=null;

private testCacheUtil(){
list=new ArrayList();
list.add("单例对象");
System.out.println(list);
}

static{
System.out.println("static 代码快!");
}
public static void main(String[] args) {
System.out.println(11);
}

        //这里提供了一个供外部访问本class的静态方法,可以直接访问   
public static testCacheUtil getInstance(){
System.out.println(22);
return instance;
}
}

这是一个经典的饿汉式单例类,  在自己内部定义自己一个实例,是不是很奇怪?注意他的构造方法,private,不支持外部来new对象,也就是说其他类只能通过getInstance()这个方法去返回第一次创建的那个实例。而且调用这个类,永远都是这么一个对象,所以它是线程安全的。但是同时这种写法也面临着资源浪费的问题。

懒汉式单例模式的写法,大同小异:

public class Singleton {
private static Singleton  instance= null;

//限制产生多个对象 

private Singleton(){
}

//通过该方法获得实例对象
public static Singleton get Instance(){

if( instance == null){
instance= new Singleton();
}

return  instance;
}
}

这种 写法其实 是线程不安全的,假设在高并发操作的情况下。则可能在内存中出现多个实例,破坏了最初的预期。为什么会出现这种情况呢?如一个线程执行到instance= new Singleton() 的时候 ,执行完这个构造方法是有时间的,另外的现程也走到这一步,判断为空的话,也会执行new 这个对象。。所以这种写法是不可取的。如果非要这么写的话,加上线程控制 ,在第一次调用的时候get Instance 加上synchronized关键字就行。推荐使用如下方式去创建单例:


public class SingletonClass{
 private static Singleton Class instance=null;
 public static SingletonClass getInstance(){
 if(instance==null){
 synchronized(SingletonClass.class){
 if(instance==null)
 instance=new SingletonClass();
 }
 }
 return instance;
 }
 private SingletonClass(){
 }
}

 是否会被jvm的gc给回收掉? 记得大学时候看过一本阎宏写的《Java与模式》这本书,书上说 不引用的话是会被垃圾回收掉的。

     这种说法是错误的。单例是静态的,设计的目的就是常用,在静态区GC(jvm的方法区(持久代))不会回收。。单例模式下类中所有实现过的数据,都不会被垃圾回收掉,比如上边编写的饿汉式单例类中的list,永久驻留内存的方式,贯穿整个web项目。单例模式中成员变量是静态的,它并不保存在堆内存中,而是在方法区中,是一块持久的内存空间,不会被自动回收,因此指向自身的引用是安全的,自身不会被回收。

public class Singleton {
private static Singleton  instance = null;

//限制产生多个对象 

private Singleton(){
}

//通过该方法获得实例对象
public static Singleton get Instance (){

if( instance  == null){
instance = new Singleton();
}

return  instance ;
}
}

使用内部类的方式实现单例,既可以做到延迟加载,也不必使用同步关键字,是一种比较完善的方式。
public  class RecordAdapter {

 

    private RecordAdapter(){}

    private static class RecordAdapterHolder{
        private static RecordAdapter adapter= new RecordAdapter();
    }

    public static RecordAdapter getAdapterInstance(){
        return RecordAdapterHolder.adapter;
    }



}


一般情况下只有一个实例,如果通过反射机制,强行调用单例类的私有构造方法,生成多个实例
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值