关于Spring在多线程下的个人疑问
在Web开发中,不可避免的是需要遇到并发操作的,并发操作就有可能会引发我们的多线程安全问题。比如说,我们多线程下访问同一个变量并且有一个线程做出修改那么就会使得我们另外的线程在不知情的情况下被修改自己的数据。
如果说当我们其中一个线程访问了成员变量Object后并且设置为null,那么其他线程访问就会出现空指针异常了。我接触线程安全问题的时候是在数据库的连接操作。刚刚学习Web开发,使用了JDBC操作,而且对于servlet还是很懵懂。在开发的时候我竟然将Connection设置为成员变量,然后有同学点醒了我,说这样会引发线程安全问题。所以,在学习Spring的时候,我也会问自己是否线程安全的问题。
1. 多线程下单例有成员变量
1.1. 测试
首先这里有一个类User:
public class User {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public long thisTime() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().toString()+"age:"+age);
age++;
return System.currentTimeMillis();
}
}
User中有一个方法thisTime 这个方法访问了age并作出了+1操作的修改。
然后我们还有一个类MulThread是用于访问User的方法thisTime:
public class MulThread extends Thread {
@Resource(name = "user")
private User user;
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().toString()+user.thisTime());
}
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
现在我们可以开启线程用于测试模拟线程下,方法thisTime的访问情况,这里我们的具体实现如下:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestMulThread {
@Resource
private MulThread th1;
@Resource
private MulThread th2;
@Test
public void test01() {
System.out.println(""+th1+th1.getUser()+"\n"+th2+th2.getUser());
th1.start();
th2.start();
//等待线程结束
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
我们接下来在Spring配置Bean:
<bean name="user" class="cn.gcc.domain.User" scope="singleton">
<property name="age" value="18" />
</bean>
<bean class="cn.gcc.test.MulThread" scope="prototype"/>
1.2. 结果
Thread[Thread-2,5,main]cn.gcc.domain.User@cad498c
Thread[Thread-3,5,main]cn.gcc.domain.User@cad498c
Thread[Thread-2,5,main]age:18
Thread[Thread-3,5,main]age:18
Thread[Thread-2,5,main]1510027754876
Thread[Thread-3,5,main]1510027754876
Thread[Thread-3,5,main]age:20
Thread[Thread-2,5,main]age:20
.......
看到上面的运行结果我们可以看到19直接被跳过了,因为age++被同时执行了两次。因此,结论就是如果是单例模式下如果方法访问了同一个成员变量那么就会引起线程不安全的问题。
1.3. 修改
我们现在如果想用单例但是又要线程安全的话该怎么办?修改如下:
我们可以加锁synchronized 我们只需要修改User的代码
public synchronized long thisTime() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().toString()+"age:"+age);
age++;
return System.currentTimeMillis();
}
Thread[Thread-2,5,main]cn.gcc.domain.User@cad498c
Thread[Thread-3,5,main]cn.gcc.domain.User@cad498c
Thread[Thread-3,5,main]age:18
Thread[Thread-3,5,main]1510028011839
Thread[Thread-2,5,main]age:19
Thread[Thread-2,5,main]1510028011939
Thread[Thread-3,5,main]age:20
....
上面的运行结果就不会有执行两次age++的情况了,因为我们对User对象加锁操作,多个线程对同一个对象不能同时访问。
当然除了上面的方法也可以修改我们的Spring配置信息,<bean name="user" class="cn.gcc.domain.User" scope="prototype">
设置成多例就不会有这种问题了
2. 多线程下SpringMVC的Controller
我们在使用SpringMVC的时候默认Controller是单例的,因此,如果在设计Bean的时候是有成员变量的请参考上面所讲的 。
还有一种就是我们方法中的参数引用的是Bean,那么这个引用是不是在多线程下是同一地址呢?
现在我们写一个controller
@Controller
public class RegisterController {
@RequestMapping(value = "/reg.action", method = RequestMethod.GET)
public String reg(){
return "reg.jsp";
}
@RequestMapping(value = "/reg.action", method = RequestMethod.POST)
public String reg2(User user){
System.out.println(user);
return "reg.jsp";
}
}
这个controller中在填入表单之后的提交过程中,form表单的各个元素SpringMVC都会帮我们封装,现在我们使用post请求去访问/reg.action然后看看结果是怎么样的
当我们使用了POST请求之后返回了reg.jsp的页面,控制台打印的信息是cn.gcc.domain.User@49cd75c3
我们再次访问后的打印信息是cn.gcc.domain.User@555b1f19,因此,结论就是SpringMVC帮我们封装后的方法引用中是不会出现线程问题的
这里SpringMVC的封装的机制我猜测是根据setter方法来封装的,而且每次封装都会通过反射机制重新新建一个对象并且注入表单的值
下面是一些关于线程安全的链接
http://blog.csdn.net/xiao__gui/article/details/8188833
http://www.cnblogs.com/doit8791/p/4093808.html
https://zhuanlan.zhihu.com/p/29587112
http://blog.csdn.net/a236209186/article/details/61460211
关于Spring在多线程下的个人疑问的更多相关文章
- 在Spring Boot框架下使用WebSocket实现聊天功能
上一篇博客我们介绍了在Spring Boot框架下使用WebSocket实现消息推送,消息推送是一对多,服务器发消息发送给所有的浏览器,这次我们来看看如何使用WebSocket实现消息的一对一发送,模 ...
- JDK动态代理给Spring事务埋下的坑!
一.场景分析 最近做项目遇到了一个很奇怪的问题,大致的业务场景是这样的:我们首先设定两个事务,事务parent和事务child,在Controller里边同时调用这两个方法,示例代码如下: 1.场景A ...
- (转)面试必备技能:JDK动态代理给Spring事务埋下的坑!
一.场景分析 最近做项目遇到了一个很奇怪的问题,大致的业务场景是这样的:我们首先设定两个事务,事务parent和事务child,在Controller里边同时调用这两个方法,示例代码如下: 1.场景A ...
- 多线程下NSOperation、NSBlockOperation、NSInvocationOperation、NSOperationQueue的使用
本篇文章主要介绍下多线程下NSOperation.NSBlockOperation.NSInvocationOperation.NSOperationQueue的使用,列举几个简单的例子. 默认情况下 ...
- 【Spring】非Spring IOC容器下获取Spring IOC上下文的环境
前言 在Spring Web项目中,有些特殊的时候需要在非Spring IOC容器下获取Spring IOC容器的上下文环境,比如获取某个bean. 版本说明 声明POM文件,指定需引入的JAR. & ...
- python 类变量 在多线程下的共享与释放问题
最近被多线程给坑了下,没意识到类变量在多线程下是共享的,还有一个就是没意识到 内存释放问题,导致越累越大 1.python 类变量 在多线程情况 下的 是共享的 2.python 类变量 在多线程情况 ...
- Java多线程21:多线程下的其他组件之CyclicBarrier、Callable、Future和FutureTask
CyclicBarrier 接着讲多线程下的其他组件,第一个要讲的就是CyclicBarrier.CyclicBarrier从字面理解是指循环屏障,它可以协同多个线程,让多个线程在这个屏障前等待,直到 ...
- Java多线程20:多线程下的其他组件之CountDownLatch、Semaphore、Exchanger
前言 在多线程环境下,JDK给开发者提供了许多的组件供用户使用(主要在java.util.concurrent下),使得用户不需要再去关心在具体场景下要如何写出同时兼顾线程安全性与高效率的代码.之前讲 ...
- 多线程下C#如何保证线程安全?
多线程编程相对于单线程会出现一个特有的问题,就是线程安全的问题.所谓的线程安全,就是如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是 ...
随机推荐
- VB.NET 中 ComboBox 如何清除选项--- 使用Dataset 赋值 DataSource 的时候
如题: 在 使用Dataset 赋值 DataSource 的时候,网络上很多都是:ComboBox2.DataSource = Null 然并卵,很高兴告诉大家:Null 在VB.NET中是没用的: ...
- Parallel.Invoke 并行的使用
Parallel类 在System.Threading.Tasks 命名空间下 下面有几个方法,这里讲一下Invoke的用法 下面我们定义几个方法方便测试 先自定义Response 防止并行的时候占 ...
- 1.ElasticSearch介绍及基本概念
一.ElasticSearch介绍 一个采用RESTful API标准的高扩展性的和高可用性的实时性分析的全文搜索工具 基于Lucene[开源的搜索引擎框架]构建 ElasticSearch是一个面向 ...
- OpenGL ES2.0贴图
1.定义传入着色器的顶点数据及索引 //传入结构体 typedef struct { ]; ]; } Vertex; //顶点数据 const Vertex Vertices[] = { {{, -, ...
- Java简单知识梳理
1. Java是单根继承结构:每个类都继承于Object类 ,这也就保证了每个对象都具备某些功能 2. Java类权限关键字: public -> protected -> default ...
- 搭建阿里云 centos mysql tomcat jdk
[toc] 阿里云使用centos 登录 http://www.aliyun.com/ 点击登录 进入控制 https://home.console.aliyun.com/ 云服务器 运行中 把ip输 ...
- python中时间日期格式化符号:
%y 两位数的年份表示(00-99) %Y 四位数的年份表示(000-9999) %m 月份(01-12) %d 月内中的一天(0-31) %H 24小时制小时数(0-23) %I 12小时制小时数( ...
- Java调度线程池ScheduledThreadPoolExecutor源码分析
最近新接手的项目里大量使用了ScheduledThreadPoolExecutor类去执行一些定时任务,之前一直没有机会研究这个类的源码,这次趁着机会好好研读一下. 该类主要还是基于ThreadPoo ...
- 【读书笔记】《写给大忙人看的Java SE 8》——Java8新特性总结
虽然看过一些Java 8新特性的资料,但是平时很少用到,时间长了就忘了,正好借着Java 9的发布,来总结下一些Java 8中的新特性. 接口中的默认方法和静态方法 先考虑一个问题,如何向Java中的 ...
- faster-rcnn中ROI_POOIING层的解读
在没有出现sppnet之前,RCNN使用corp和warp来对图片进行大小调整,这种操作会造成图片信息失真和信息丢失.sppnet这个模型推出来之后(关于这个网络的描述,可以看看之前写的一篇理解:ht ...