Java web 入门——3.springMVC中的线程安全问题

2019-12-01  本文已影响0人  卓三阳

1.基础

web容器本身就是多线程的,每一个HTTP请求都会使用一个独立的线程;
Spring中的bean(用@Repository、@Service、@Component和@Controller注册的bean)默认都是单例的,即整个程序、所有线程共享一个实例;
Spring提供的模板类(XXXTemplate),使用了ThreadLocal,使各线程能够保持各自独立的一个对象,其实就是一个变量副本,实现了线程安全,如:JdbcTemplate;
spring的Bean中的自定义的成员变量除非进行threadlocal封装,或者将Bean声明为prototype型,否则都是非线程安全的!
一个类中的方法实际上是独立,方法内定义的局部变量在每次调用方法时都是独立的,不会有并发问题。只有类的属性/全局变量会导致多线程问题


2.java 多线程调用单例类的同一个方法

每当启用一个线程时,JVM就为他分配一个Java栈,栈是以帧为单位保存当前线程的运行状态。某个线程正在执行的方法称为当前方法,当前方法使用的栈帧称为当前帧,当前方法所属的类称为当前类,当前类的常量池称为当前常量池。当线程执行一个方法时,它会跟踪当前常量池。

每当线程调用一个Java方法时,JVM就会在该线程对应的栈中压入一个帧,这个帧自然就成了当前帧。当执行这个方法时,它使用这个帧来存储参数、局部变量、中间运算结果等等。

Java栈上的所有数据都是私有的。任何线程都不能访问另一个线程的栈数据。所以我们不用考虑多线程情况下栈数据访问同步的情况。


3.spring bean的5种作用域

3.1 spring bean的5种作用域

当spring创建applicationContext容器的时候,spring会欲初始化所有的该作用域实例,加上lazy-init就可以避免预处理;

每次通过getBean获取该bean就会新产生一个实例,创建后spring将不再对其管理;

搞web的大家都应该明白request的域了吧,就是每次请求都新产生一个实例,和prototype不同就是创建后,接下来的管理,spring依然在监听

每次会话,同上

全局的web域,类似于servlet中的application

3.2 为什么Spring MVC Controller层,Service层和Dao层默认使用单例

单例模式是spring推荐的配置,它在高并发下能极大的节省资源,提高服务抗压能

但是单例模式下会共享普通成员变量和静态成员变量,在多线程环境下是不安全的。Service层、Dao层用默认singleton就行,虽然Service类也有dao这样的属性,但dao这些类都是没有状态信息的,也就是 相当于不变(immutable)类。Controller层如果有定义可变的成员变量,就需要配置成多例。


4最佳实践

1、在开发中,springMVC优先使用单例模式,而且尽量不要在controller中设定成员变量
2、万一必须要定义一个非静态成员变量时候,则通过注解@Scope("prototype"),将其设置为多例模式
3、总的来说就是,单例模式因为大大节省了实例的创建和销毁,有利于提高性能,而ThreadLocal用来保证线程安全性。

上一篇下一篇

猜你喜欢

热点阅读