单例模式
Posted 痴生-永生富贵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式相关的知识,希望对你有一定的参考价值。
关于单例模式,先来说一个大家都知道的例子,spring中的Dao层用的就是单例,顾名思义,就是整个程序运行过程中,就只有一个dao,dao是和数据库打交道的,实际运行过程中,不可避免的会有多个线程访问数据库,这个时候如果不加什么措施的话,那么程序肯定是线程不安全的,想想看,一个线程刚刚获得了数据库的连接,另一个线程随之立刻获得了数据库的连接,那么前一个线程的数据库连接以及之后的执行就会被覆盖取消。。。
如何保证每个线程对数据库的操作相互独立呢?java提供了一个threadlocal对象,我们可以用它来实现在单例模式下线程之间的独立运行。
不光如此,spring中的action,service层配置一般默认都是单例模式,有这么一句话,单例是线程不安全的,这取决于对象是否包含成员变量,如果包含,比如说上面的dao包含对数据库的连接,这个时候需要额外的处理才能保证线程安全,如果没有成员变量,那么自然是线程安全的,比如说action,service(只做一般的方法调用)。
下面是单例模式的基础实现。
1 懒汉式
1 public class SingleDemo1 { 2 private static SingleDemo1 singleDemo1; 3 private SingleDemo1(){ } 4 public static SingleDemo1 getBean() { 5 if(singleDemo1 == null) 6 { 7 singleDemo1=new SingleDemo1(); 8 } 9 return singleDemo1; 10 } 11 }
2 饿汉式
1 public class SingleDemo1 { 2 private static SingleDemo1 singleDemo1=new SingleDemo1(); 3 private SingleDemo1(){ } 4 public static SingleDemo1 getBean() { 5 return singleDemo1; 6 } 7 }
两种实现有什么区别呢?懒汉式的初始化是在真正需要获取单例时发生的,而饿汉式则是在类加载时就已经初始化,两者存在于内存中的时间长短不一,第一次获取单例的等待时间长短不一,视情况而定。
另外,懒汉式的实现是线程不安全的,我们可以用synchronized来实现同步,相比于修饰方法,修饰代码块显然效率更高,因为我们可以只修饰可能导致线程不安全的那一段代码,修改如下:
1 public class SingleDemo1 { 2 private static volatile SingleDemo1 singleDemo1; 3 private SingleDemo1(){ } 4 public static SingleDemo1 getBean() { 5 if(singleDemo1 == null) 6 { 7 synchronized (singleDemo1) { 8 if(singleDemo1 == null){ 9 singleDemo1=new SingleDemo1(); 10 } 11 } 12 } 13 return singleDemo1; 14 } 15 }
至于为什么要volatile,则是为了保证单例对象是最新的,不然会导致第二个if判断没有意义。
上面只是单例的基础实现,实际应用中不可能像例子中这么简单,或许还会有一些状态等,比如说有些应用中会有local_cache这个变量,用来记录代码中经常需要用到的一些数据,这些数据会在不同的层中被调用,这个时候还需要通过使用threadlocal来保证每个线程的cache相互独立。
另外,在某些情况下,单例会失效,比如说反射,序列化。
以上是关于单例模式的主要内容,如果未能解决你的问题,请参考以下文章