分析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()这个方法去返回第一次创建的那个实例。而且调用这个类,永远都是这么一个对象,所以它是线程安全的。但是同时这种写法也面临着资源浪费的问题。
懒汉式单例模式的写法,大同小异:
private static Singleton instance= null;
//限制产生多个对象
private Singleton(){
}
//通过该方法获得实例对象
public static Singleton get Instance(){
if( instance == null){
instance= new Singleton();
}
return instance;
}
}
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项目。单例模式中成员变量是静态的,它并不保存在堆内存中,而是在方法区中,是一块持久的内存空间,不会被自动回收,因此指向自身的引用是安全的,自身不会被回收。
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;
}
}