在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在多线程下的个人疑问的更多相关文章

  1. 在Spring Boot框架下使用WebSocket实现聊天功能

    上一篇博客我们介绍了在Spring Boot框架下使用WebSocket实现消息推送,消息推送是一对多,服务器发消息发送给所有的浏览器,这次我们来看看如何使用WebSocket实现消息的一对一发送,模 ...

  2. JDK动态代理给Spring事务埋下的坑!

    一.场景分析 最近做项目遇到了一个很奇怪的问题,大致的业务场景是这样的:我们首先设定两个事务,事务parent和事务child,在Controller里边同时调用这两个方法,示例代码如下: 1.场景A ...

  3. (转)面试必备技能:JDK动态代理给Spring事务埋下的坑!

    一.场景分析 最近做项目遇到了一个很奇怪的问题,大致的业务场景是这样的:我们首先设定两个事务,事务parent和事务child,在Controller里边同时调用这两个方法,示例代码如下: 1.场景A ...

  4. 多线程下NSOperation、NSBlockOperation、NSInvocationOperation、NSOperationQueue的使用

    本篇文章主要介绍下多线程下NSOperation.NSBlockOperation.NSInvocationOperation.NSOperationQueue的使用,列举几个简单的例子. 默认情况下 ...

  5. 【Spring】非Spring IOC容器下获取Spring IOC上下文的环境

    前言 在Spring Web项目中,有些特殊的时候需要在非Spring IOC容器下获取Spring IOC容器的上下文环境,比如获取某个bean. 版本说明 声明POM文件,指定需引入的JAR. & ...

  6. python 类变量 在多线程下的共享与释放问题

    最近被多线程给坑了下,没意识到类变量在多线程下是共享的,还有一个就是没意识到 内存释放问题,导致越累越大 1.python 类变量 在多线程情况 下的 是共享的 2.python 类变量 在多线程情况 ...

  7. Java多线程21:多线程下的其他组件之CyclicBarrier、Callable、Future和FutureTask

    CyclicBarrier 接着讲多线程下的其他组件,第一个要讲的就是CyclicBarrier.CyclicBarrier从字面理解是指循环屏障,它可以协同多个线程,让多个线程在这个屏障前等待,直到 ...

  8. Java多线程20:多线程下的其他组件之CountDownLatch、Semaphore、Exchanger

    前言 在多线程环境下,JDK给开发者提供了许多的组件供用户使用(主要在java.util.concurrent下),使得用户不需要再去关心在具体场景下要如何写出同时兼顾线程安全性与高效率的代码.之前讲 ...

  9. 多线程下C#如何保证线程安全?

    多线程编程相对于单线程会出现一个特有的问题,就是线程安全的问题.所谓的线程安全,就是如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是 ...

随机推荐

  1. Pro Flight YOKE 设备键位映射踩过的坑

    背景 VR游戏项目.街机游戏项目7月阶段版本快要结束了,考虑到带有键鼠外设显得逼格比较Low,所以决定采用"高大上"的专业设备来进行游戏操作. 需求 需要将键盘鼠标操作的18个键位 ...

  2. Redis学习——redis.conf 配置文件介绍

    学以致用 学在用前 参看文章: redis.conf 配置详解 Redis配置文件详解(redis.conf)-云栖社区 在Redis的使用过程,除了知道对Redis五种数据类型的操作方法之外,最主要 ...

  3. Python自学笔记-面向对象编程(Mr seven)

    类的成员可以分为三大类:字段.方法和属性. 一.字段 字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同, 普通字段属于对象 静态字段属于类 二.方法 方法 ...

  4. python之控制台(console)颜色显示

    #coding=utf-8 import ctypes,sys STD_INPUT_HANDLE = -10 STD_OUTPUT_HANDLE = -11 STD_ERROR_HANDLE = -1 ...

  5. python修改注册表

    与注册表操作相关的函数可以分为打开注册表.关闭注册表.读取项值.c添加项值.添加项,以及删除项等几类. 表1   Windows注册表基本项 项名 描述 HKEY_CLASSES_ROOT 是HKEY ...

  6. 有关 Hybrid 开发模式实践总结

    前言 随着公司业务不断发展,移动开发项目越来越多,项目任务时间紧,我们内部开发流程是以项目为导向,有别于一般公司对产品不断迭代的做法,但移动端开发人员资源有限,需要在不同项目之间做业务场景切换开发,就 ...

  7. IDL 数组运算

    1.求大.求小和求余 IDL> arr=indgen(4) IDL> print,arr 0 1 2 3 IDL> print,arr>3 3 3 3 3 IDL> pr ...

  8. iOS如何提高页面流畅度

    A.提高CPU性能 对象创建1.尽量用轻量的对象代替重量的对象,比如CALayer 比 UIView 要轻量许多,如果不考虑交互事件的话,可以选择CALayer.2.Storyboard和xib加载对 ...

  9. [置顶] win10 uwp 参考

    态度随意申请专栏,没想到通过 看了我的博客,都是在别的大神博客看到,然后修改他们的 我看到的大神博客 东邪独孤 http://www.cnblogs.com/tcjiaan/ 老周,买了他的<W ...

  10. JavaFX引入资源问题

    描述 - 使用javafx 引入资源的时候 抛出异常 在swing引入资源 采取相对路径即可,而javafx不是 ImageView imageNode = (ImageView) root.look ...