在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. Linux入门之常用命令(9)进程及端口查看

    [Linux下查看进程] 查看程序对应进程号:ps –ef|grep 程序名 查看进程占用端口:ss -pl | grep 进程号 [通过进程查看端口] 查看占用的端口号:netstat –nltp| ...

  2. NOIP2017SummerTraining0705

    个人感受:这一场考试是网开着的,然后第一题就水过了,第二三题应该是暴力吧,然后各水了50.拿了200分.排名第10. 问题 A: 重复字符串 时间限制: 1 Sec  内存限制: 256 MB提交: ...

  3. Centos7搭建swarm集群

    1. 准备 两台虚拟机,IP分别为: 192.168.1.104 192.168.1.105 保证能互相 ping 通 2. 修改虚拟机的 host,分别任 c1.c2 在 192.168.1.105 ...

  4. java中log4j学习笔记

    Log4j是apache的一个开源项目,用来操作程序日志信息的框架.因便于管理,在工程中用来代替System.out打印语句.通过配置Log4j中的log4j.properties,可以指定日志信息的 ...

  5. asp.net中配置使用Sqlite轻型数据库

    Sqlite 管理工具 SQLiteDeveloper及破解 功能特点 表结构设计,数据维护,ddl生成,加密数据库支持,sqlite2,3支持 唯一缺憾,收费,有试用期 破解方法: 注册表删除 HK ...

  6. JavaScript设计模式--门面模式

    外部与一个子系统的通信必须通过一个系统的一个门面对象进行,这就是门面模式. 门面模式具备如下两个角色: 1. 门面角色 客户端可以调用这个角色方法,此角色中有子系统的应用(知晓相关的(一个或多个)子系 ...

  7. Codeforces A. Trip For Meal

    A. Trip For Meal time limit per test 1 second memory limit per test 512 megabytes input standard inp ...

  8. Spring 源码剖析IOC容器(一)概览

    目录 一.容器概述 二.核心类源码解读 三.模拟容器获取Bean ======================= 一.容器概述 spring IOC控制反转,又称为DI依赖注入:大体是先初始化bean ...

  9. 关于extjs表单布局的几种方式

    一.用column布局 layout:'column', defaults:{ style:'float:left;margin:4px;', columnWidth: 0.49, msgTarget ...

  10. memcached+狀態模式+工廠方法使用

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...