Servlet 是否是线程安全的 Spring MVC 线程是否安全
Servlet是单例多线程的无需置疑;多线存在共享实例时易发生线程不安全问题

单例多线程:一个线程中只有一个实例对象,但是如果在多线程的环境中,就会出现多个实例的情况,这样就不是单例模式了,
此时就容易发生线程不安全问题。
线程不安全问题详解:
多个线程之间是不能直接传递数据交互的,它们之间的交互只能通过共享变量来实现。

根据JMM的设计,系统存在一个主内存(Main Memory),Java中所有实例变量都储存在主存中,对于所有线程都是共享的。
每条线程都有自己的工作内存(Working Memory),工作内存由缓存和堆栈两部分组成,缓存中保存的是主存中变量的拷贝,
缓存可能并不总和主存同步,也就是缓存中变量的修改可能没有立刻写到主存中;
堆栈中保存的是线程的局部变量,线程之间无法相互直接访问堆栈中的变量。


 

 

每个Servlet会根据请求来新建线程

也就是说你接到一个请求到Servlet,这个Servlet就会运行一个Tread

 

 

 

Java线程的两个特性,可见性和有序性。

多个线程之间是不能直接传递数据交互的,它们之间的交互只能通过共享变量来实现。拿上面的例子来说明,在多个线程之间共享了Count类的一个对象,这个对象是被创建在主内存(堆内存)中,每个线程都有自己的工作内存(线程栈),工作内存存储了主内存count对象的一个副本,当线程操作count对象时,首先从主内存复制count对象到工作内存中,然后执行代码count.count(),改变了num值,最后用工作内存中的count刷新主内存的 count。当一个对象在多个工作内存中都存在副本时,如果一个工作内存刷新了主内存中的共享变量,其它线程也应该能够看到被修改后的值,此为可见性。

 

多个线程执行时,CPU对线程的调度是随机的,我们不知道当前程序被执行到哪步就切换到了下一个线程,

一个最经典的例子就是银行汇款问题,一个银行账户存款100,这时一个人从该账户取10元,同时另一个人向该账户汇10元,那么余额应该还是100。那么此时可能发生这种情况,A线程负责取款,B线程负责汇款,A从主内存读到100,B从主内存读到100,A执行减10操作,并将数据刷新到主内存,这时主内存数据100-10=90,而B内存执行加10操作,并将数据刷新到主内存,最后主内存数据100+10=110,显然这是一个严重的问题,我们要保证A线程和B线程有序执行,先取款后汇款或者先汇款后取款,此为有序性。

 

Spring mvc 线程不安全的原因
请求时多线程请求的,但是每次请求过来调用的Controller对象都是一个,而不是一个请求过来就创建一个controller对象

原因就在于如果这个controller对象是单例的,那么如果不小心在类中定义了类变量,那么这个类变量是被所有请求共享的,

这可能会造成多个请求修改该变量的值,出现与预期结果不符合的异常

在单例的情况下 相当于所有类变量对于每次请求都是共享的,每一次请求对类变量的修改都是有效的

那有没有办法让controller不以单例而以每次请求都重新创建的形式存在呢?

答案是当然可以,只需要在类上添加注解@Scope("prototype")即可,这样每次请求调用的类都是重新生成的(每次生成会影响效率

 

还有其他方法么?

答案是肯定的!

使用ThreadLocal 来保存类变量,将类变量保存在线程的变量域中,让不同的请求隔离开来

阅读更多
个人分类: java基础
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

Servlet 是否是线程安全的 Spring MVC 线程是否安全

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭