Spring并发访问的线程安全性问题

springmvc的controller是singleton的(非线程安全的),这也许就是他和struts2的区别吧
和Struts一样,Spring的Controller默认是Singleton的,这意味着每个request过来,系统都会用原有的instance去处理,这样导致了两个结果:一是我们不用每次创建Controller,二是减少了对象创建和垃圾收集的时间;由于只有一个Controller的instance,当多个线程调用它的时候,它里面的instance变量就不是线程安全的了,会发生窜数据的问题。

当然大多数情况下,我们根本不需要考虑线程安全的问题,比如dao,service等,除非在bean中声明了实例变量。因此,我们在使用spring mvc 的contrller时,应避免在controller中定义实例变量。 
如:

public class Controller extends AbstractCommandController {
......
protected ModelAndView handle(HttpServletRequest request,HttpServletResponse response,
            Object command,BindException errors) throws Exception {
company = ................;
}
protected Company company;
}  

在这里有声明一个变量company,这里就存在并发线程安全的问题。
如果控制器是使用单例形式,且controller中有一个私有的变量a,所有请求到同一个controller时,使用的a变量是共用的,即若是某个请求中修改了这个变量a,则,在别的请求中能够读到这个修改的内容。。

有几种解决方法:
1、在Controller中使用ThreadLocal变量
2、在spring配置文件Controller中声明 scope="prototype",每次都创建新的controller
所在在使用spring开发web 时要注意,默认Controller、Dao、Service都是单例的。

【1】SpringMVC多线程环境中如何保证对象的安全性?

代码如下:

@RequestMapping("/user")
@Controller
Class UserController
{
    @Resource
    UserService userService;  

    @RequestMapping("/add")
    public void testA(User user){
        userService.add(user);
    }  

    @RequestMapping("/get")
    public void testA(int id){
        userService.get(id);
    }
}  

@Service("userService")
Class UserService{  

    public static Map<Integer,User> usersCache = new HashMap<String,User>();  

    public void add(User user){
        usersCache.put(user.getId(),user);
    }  

    public void get(int id){
        usersCache.get(id);
    }  

}

此段代码,usersCache对象就是线程不安全的。因为它是静态的全局共享对象。如果有多个线程同时调用add方法,可能会发生用户对象被覆盖的情况,也就是id对应对象不一致,这是多线程编程中最常发生的事情。

所以,可以使用 Collections 工具同步Map。

static Map<Integer, Users> usersCache = Collections.synchronizedMap(new HashMap<Integer, Users>());

研究一下,Spring中的源码,它对常用的开源框架做了大量封装,如,Hibernate中的sessionFactory,就使用的是 org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean,而在 AnnotationSessionFactoryBean的父类LocalSessionFactoryBean中,定义了大量的ThreadLocal来保证多线程的安全性。

public class LocalSessionFactoryBean extends AbstractSessionFactoryBean implements BeanClassLoaderAware {  

    private static final ThreadLocal<DataSource> configTimeDataSourceHolder =
            new ThreadLocal<DataSource>();  

    private static final ThreadLocal<TransactionManager> configTimeTransactionManagerHolder =
            new ThreadLocal<TransactionManager>();  

    private static final ThreadLocal<Object> configTimeRegionFactoryHolder =
            new ThreadLocal<Object>();  

    private static final ThreadLocal<CacheProvider> configTimeCacheProviderHolder =
            new ThreadLocal<CacheProvider>();  

    private static final ThreadLocal<LobHandler> configTimeLobHandlerHolder =
            new ThreadLocal<LobHandler>();  
时间: 2024-08-07 08:37:35

Spring并发访问的线程安全性问题的相关文章

Spring 并发访问的线程安全性问题

首先对于Spring的IOC来说,对象是由Spring来帮我们管理,也就是在Spring启动的时候,在Spring容器中,由Spring给我们创建的,Spring会帮我们维护,一般都是单例的,也就是一个对象. spring生成对象默认是单例的.通过scope属性可以更改为多例. 第一部分:验证Spring生成对象默认是单例的. 下面我们来一个网上的例子验证一下: <bean id="singleton" class="java.util.Date" scope

Springmvc 并发访问的线程安全性问题

首先对于spring的IOC来说,对象是由Spring来帮我们管理,也就是在Spring启动的时候,在Spring容器中,由Spring给我们创建的,Spring会帮我们维护,一般都是单例的,也就是一个对象. spring生成对象默认是单例的.通过scope属性可以更改为多例. 第一部分:验证Spring生成对象默认是单例的. 下面我们来一个网上的例子验证一下: [html] view plain copy print? <bean id="singleton" class=&q

并发编程初探-线程安全性

在Java并发编程中,对于线程安全是非常重要的,也是必须要考虑的一个问题.可以这么说,只要涉及到网络的,都必须考虑线程安全问题.好了,开始噼里啪啦地开始敲代码之前,我觉得有必要了解一些文绉绉的理论知识,因为这些理论知识是我们敲出来的代码是否是线程安全的一个依据. 当多个线程访问某个状态变量并且其中有一个线程执行写入操作的时候,必须考虑采用同步机制来协同这些线程对变量的访问,Java中的主要同步机制是关键字synchronized,它提供了一种独占的加锁方式,但"同步"这个术语还包括类型的变量,显

并发基础知识 — 线程安全性

前段时间看完了<并发编程的艺术>,总感觉自己对于并发缺少一些整体的认识.今天借助<Java并发编程实践>,从一些基本概念开始,重新整理一下自己学过并发编程.从并发基础开始,深入进去,系统学习一下并发编程. 编写线程安全的代码,核心在于要对状态访问操作进行管理,特别是对共享的(Shared)和可变的(Mutable)状态的访问.对象的状态是指存储在状态变量(实例或静态域)中的数据.对象的状态还可能包括其他依赖对象的域.(Map.Entry) 一个对象是否需要时线程安全的,取决于该对象

并发编程之线程安全性

一.什么是线程安全性 并发编程中要编写线程安全的代码,则必须对可变的共享状态的访问操作进行管理. 对象的状态就是存储在实例或者静态变量中的数据,同时其状态也包含其关联对象的字段,比如字典集合既包含自己的状态, 也包含KeyValuePair. 共享即可以多个线程同时访问变量,可变即变量在其声明周期内可以发生变化. 代码线程安全性关注的是防止对数据进行不可控的并发访问. 是否以多线程的方式访问对象,决定了此对象是否需要线程安全性.线程安全性强调的是对对象的访问方式,而不是对象 要实现的功能.要实现

软件构造 并发3(线程安全性)

线程安全:数据类型或静态方法在多线程中执行时,无论如何执行,不需调用者做额外的协作仍可以得到正确的行为. 行为正确意味着满足规格说明和保持不变性   不能在前置条件中对调用者增加时间性要求(在set()运行时不能调用get()) 例子:迭代器, 不是线程安全的. 迭代器的规范说,不能在迭代它的同时修改一个集合. 这是一个与调用者相关的时间相关的前提条件,如果违反它,Iterator不保证行为正确 线程安全的四个方法:①限制可变变量的共享②用不可变的共享变量③将共享数据封装在线程安全的数据类型中④

软件构造 并发3(线程安全性)----锁定和同步

同步:防止线程同时访问共享数据. 锁:是一种抽象,最多允许一个线程拥有它. 保持锁定是一条线程告诉其他线程的:我正在改变这  个东西,现在不要触摸它 两个操作:获取允许线程获取锁的所有权. 如果一个线程试图获取当前由另一个线程拥有的锁,它将阻塞,直到另一个线程释放该锁. 此时,它将与任何其他尝试获取锁的线程竞争. 一次只能有一个线程拥有该锁.释放锁的所有权,允许另一个线程获得它的所有权 使用锁还会告知编译器和处理器您正在同时使用共享内存,以便将寄存器和高速缓存刷新到共享存储. 这可以确保锁的所有

Java线程安全性中的对象发布和逸出

发布(Publish)和逸出(Escape)这两个概念倒是第一次听说,不过它在实际当中却十分常见,这和Java并发编程的线程安全性就很大的关系. 什么是发布?简单来说就是提供一个对象的引用给作用域之外的代码.比如return一个对象,或者作为参数传递到其他类的方法中. 什么是逸出?如果一个类还没有构造结束就已经提供给了外部代码一个对象引用即发布了该对象,此时叫做对象逸出,对象的逸出会破坏线程的安全性. 概念我们知道了,可我们要关注什么地方呢?我们要关注的时候就是逸出问题,在不该发布该对象的地方就

JAVA并发编程实战 读书笔记(一)线程安全性

线程安全性   1.什么是线程安全 在线程安全的定义中,最核心的概念是正确性.正确性的含义是,某个类的行为与规范完全一致.当对正确性有了一个比较清晰的定义后,就可以定义线程安全性:当多个线程访问某个类时,这个类始终能表现出正确的行为,那这个类就是线程安全的. 举例:无状态对象一定是线程安全的. 大多数Servlet都是无状态的,当Servlet在处理请求时需要保存一些信息时,线程安全才会成为一个问题. 2.原子性 举个例子:语句 ++i:虽然递增操作++i是一种紧凑的语法,使其看上去是一个操作,