在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. kbhit()

    kbhit() 非阻塞的响应键盘输入时间   C++函数 功能和返回值:检查是否有键盘输入 ,有返回非0 ,无返回0 int khbit(void) 头文件: #include<conio.h& ...

  2. 【POJ】1704 Georgia and Bob(Staircase Nim)

    Description Georgia and Bob decide to play a self-invented game. They draw a row of grids on paper, ...

  3. angular学习-01,使用第三方库(jquery...)

    开发环境(window) 1.安装node  https://nodejs.org/en/ 2.安装angular-cli npm install -g @angular/cli 3.使用ng new ...

  4. .NET十年回顾

    一.   引子 从我还是编程菜鸟时起,.NET就从来没让我失望过.总是惊喜不断. 当年我第一个项目是做个进销存.用的Winform.当时我是机电工程师.编程只是业余心血来潮而已. .NET的低门槛.V ...

  5. R语言包下载(转载)

    http://blog.csdn.net/hongjinlongno1/article/details/53130893 包含几乎所有包,很方便

  6. 技术领导(Technical Leader)画像

    程序员都讨厌被管理,而乐于被领导.管理的角色由PM(project manager)扮演,具体来说,PM负责提需求.改改改.大多数情况,PM是不懂技术的,这也是程序员觉得PM难以沟通的原因.而后者由技 ...

  7. 【转】 中兴OLT-C300常用命令

    中兴OLT C300show running-config (加载各种板卡)show gpon onu uncfg (查看OLT所有未配置的ONU)show gpon onu uncfg gpon-o ...

  8. zoj 1884 简单 键盘 字符 处理

    WERTYU Time Limit: 2 Seconds      Memory Limit: 65536 KB A common typing error is to place the hands ...

  9. Js全选 添加和单独删除

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. 知识树杂谈Java面试(4)

    一. Java集合 1.  集合分类:  Collection.Map. 2. Collection: 3. Map 4. 注意点 a. List 有序.可重复:Set 无序.不可重复:Map  键值 ...