单例的好处:
1 减少请求时候创建对象的开销,提升性能
2 减少jvm垃圾回收
单例的坏处:
1 对于有状态的变量可能会造成线程安全问题,因为只有一个实例,如果操作的是有状态的全局变量,多个线程之间可能会操作同一个变量和对象导致线程不安全问题
多例的好处:
1 线程安全,每个请求过来都分配一个新的对象,里面的所有东西属性方法都是该线程独享的
坏处:
1 资源开销大,创建对象需要消耗性能
2 会产生大量的垃圾对象
Spring框架中的bean 或者说组件,默认是单例的。
单例模式确保了某个类只有一个实例,并且自行实例化,向整个系统提供这个实例。
在多线程的情况下,Web容器会向每个请求分配一个线程。这些线程会执行对应的业务逻辑。如果在执行的时候对单例对象进行了修改,则必须考虑到线程同步的问题。
同步机制
ThreadLocal 和 线程同步机制
线程同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题。
ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
在spring 中是使用 ThreadLocal 解决线程安全问题
线程安全问题主要是全局变量和静态变量引起的。
若每个线程中对全局变量、静态变量读操作,而无写操作,一般来说这个全局变量是线程安全的。
若多个线程同时执行写操作,需要考虑线程同步问题,否则影响线程安全。
spring 使用ThreadLocal 实现高并发下 共享资源的同步。
原理:
为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线
程都完全拥有该变量。【每个线程其实是改变的是自己线程的副本,而不是真正要改变的变量,所以效果就是每个线程都有自己的,“这其实就将共享变相为人人有份!”】
ThreadLocal 如何实现为每一个变量维护变量的副本。
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}