首页 > 代码库 > 单例模式与多线程之间的关系总结

单例模式与多线程之间的关系总结

  近日笔者被多线程与单例对象之间的关系产生了混淆。通过了一段时间的查阅,理清了两者之间的管理,现做笔记梳理。如有不足,欢迎指出:)

在我在考虑考虑他们的时候思考了以下几个问题:

1、我们通常都将dao层(数据库连接层)设置成单例,这样的话如果每次处理数据库中的数据都需要同一个对象去处理的话,处理数据的性能完全得不到保证。

2、ssh中为什么struts2中的action层必须创建多例?而ssm中springmvc的Controller层不需要创建多例?

3、一个单例模式创建的对象是可以同时被多个线程处理的,如果一个对象被多个线程同时处理的话,很有可能出现线程同步问题(关于线程中的安全问题,对对象加锁请参考:http://lavasoft.blog.51cto.com/62575/99155/),如果两个线程同时访问一个函数的话,要不要加锁呢,加锁怎么加,不加又怎样?

 

理解思路:

  我们知道一个对象是可以同时被多个线程进行调用的,一个单例对象每次都只能有一个线程进行调用的话,就不会出现线程中的安全问题了。只有一个当一个对象加锁后,才能做到每次只能有一个线程进行处理。

  多个线程处理一个对象的过程是怎么样的呢?每次创建一个线程,jvm虚拟机就会在内存中给每个线程分配独立的堆栈存储空间

  

  单例模式创建的对象在内存中是如何加载的呢?所有的单例模式的对象都是通过静态方法获取的,也就是说,每个单例模式的对象都是存储在静态共享区中!

  一个普通对象在一个线程中是怎么加载的呢?

技术分享

  在一个线程中,如果创建一个对象,会先在堆内存中开辟一个存储空间,该对象在创建的时候就会在栈内存中开辟空间,调用其构造方法、静态代码块等…当方法结束,会在栈内存中清除。一个线程在调用这个对象的方法的时候会在栈内存中创建一个空间存储对象方法。

  同理,对于在一个线程加载单例模式对象的时候,它会在静态共享区获取单例对象,然后在调用对象方法(非静态)的时候会在自己的栈内存开辟一个空间,所以每个线程在调用同一个对象的方法的时候都会在它的栈内存中开辟一个独立的内存空间。这说明了多线程处理同一个对象的时候如果不涉及到对象的共有属性值,不会存在线程安全问题。

   现在对文章开头的内容进行一点解释:

1、我们通常都将dao层(数据库连接层)设置成单例,这样的话如果每次处理数据库中的数据都需要同一个对象去处理的话,处理数据的性能完全得不到保证。

  答:因为我们每次处理数据库是使用session进行数据库的交互处理,而session是由SessionFactory创建的,SessionFactory将创建出的session放入session连接池中,连接池中的session均为不同的对象。我们指的创建单例对象在这里指的是SessionFactory。

2、ssh中为什么struts2中的action层必须创建多例?而ssm中springmvc的Controller层不需要创建多例?

  答:struts2中因为将前端获取的值全部都存储在对象属性中,所以肯定需要设置为多例,springMVC中,前端获取的值直接进入方法中,所以设置为单例模式不会存在线程安全问题。

3、一个单例模式创建的对象是可以同时被多个线程处理的,如果一个对象被多个线程同时处理的话,很有可能出现线程同步问题(关于线程中的安全问题,对对象加锁请参考:http://lavasoft.blog.51cto.com/62575/99155/),如果两个线程同时访问一个函数的话,要不要加锁呢,加锁怎么加,不加又怎样?

   答:一个单例模式的方法可以同时被多个线程处理,多个线程如果不是同时处理一个对象的共有属性,则不会出现线程问题,即使是方法中的属性如果两个线程同时访问同一个方法的时候,如果这个方法中没有共有的属性,则不需要加锁,反之则需要加锁。

单例模式与多线程之间的关系总结