关于Spring在多线程下的个人疑问
来源:互联网 发布:剑灵秦义绝捏脸数据图 编辑:程序博客网 时间:2024/06/06 00:12
在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@cad498cThread[Thread-3,5,main]cn.gcc.domain.User@cad498cThread[Thread-2,5,main]age:18Thread[Thread-3,5,main]age:18Thread[Thread-2,5,main]1510027754876Thread[Thread-3,5,main]1510027754876Thread[Thread-3,5,main]age:20Thread[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@cad498cThread[Thread-3,5,main]cn.gcc.domain.User@cad498cThread[Thread-3,5,main]age:18Thread[Thread-3,5,main]1510028011839Thread[Thread-2,5,main]age:19Thread[Thread-2,5,main]1510028011939Thread[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
@Controllerpublic 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的一些疑问
- 关于在Windows下用键盘输入EOF的一些疑问
- 关于“关于C#装箱的疑问”帖子的个人看法
- 关于前篇提到的几个疑问的个人理解
- 关于多线程的个人理解
- 关于在ubuntu下用Qt写C++程序时字符编码的疑问
- 关于在ADS环境下使用libc库函数的一些疑问
- Spring的疑问若干
- Spring的疑问若干
- Spring的疑问若干
- 关于java多线程的个人解答
- 关于javascript的疑问
- 关于变压器的疑问
- 关于 LoadLibrary 的疑问
- 关于junit的疑问
- 关于pthread_testcancel()的疑问
- VTK学习(五)三维场景基本要素
- 微信小程序官方开发文档
- spring与mybatis三种整合方法
- android js 互调
- 欢迎使用CSDN-markdown编辑器
- 关于Spring在多线程下的个人疑问
- 《Metasploit 魔鬼训练营》04 Web 应用渗透测试
- android横竖屏管理
- OSI七层协议解释
- 生成简单流水号
- rowid的组成
- C/C++之回调函数
- leetcode(2):Add Two Numbers
- 解决MyBatis进行数据库操作时因参数过长导致打印日志过长的问题