加入收藏 | 设为首页 | 会员中心 | 我要投稿 河北网 (https://www.hebeiwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

Synchronized锁在Spring事宜打点下,为啥还线程不安详?

发布时间:2019-03-16 03:02:32 所属栏目:建站 来源:Java3y
导读:媒介 只有秃顶才气变强。 文本已收录至我的GitHub客栈,接待Star:https://github.com/ZhongFuCheng3y/3y 伴侣问了我一个技能的题目(伴侣其实是勤学,服气!) 该题目来历知乎(synchronized锁题目): https://www.zhihu.com/question/277812143 开启10000个
副问题[/!--empirenews.page--]

媒介

只有秃顶才气变强。

文本已收录至我的GitHub客栈,接待Star:https://github.com/ZhongFuCheng3y/3y

伴侣问了我一个技能的题目(伴侣其实是勤学,服气!)

该题目来历知乎(synchronized锁题目):

https://www.zhihu.com/question/277812143

开启10000个线程,每个线程给员工表的money字段【初始值是0】加1,没有行使气馁锁和乐观锁,可是在营业层要领上加了synchronized要害字,题目是代码执行完毕后数据库中的money 字段不是10000,而是小于10000 题目出在那边?

Service层代码:

Synchronized锁在Spring事宜打点下,为啥还线程不安详?

SQL代码(没有加气馁/乐观锁):

用1000个线程跑代码:

简朴来说:多线程跑一个行使synchronized要害字修饰的要领,要领内操纵的是数据库,按正常逻辑应该最终的值是1000,但颠末多次测试,功效是低于1000。这是为什么呢?

一、我的思索

既然测试出来的功效是低于1000,那声名这段代码不是线程安详的。不是线程安详的,那题目呈此刻哪呢?众所周知,synchronized要领可以或许担保所修饰的代码块、要领担保有序性、原子性、可见性。

讲原理,以上的代码跑起来,题目中Service层的increaseMoney()是有序的、原子的、可见的,以是断定跟synchronized应该不要紧。

(参考我之前写过的synchronize锁条记:Java锁机制相识一下)

既然Java层面上找不到缘故起因,那说明一下数据库层面的吧(由于要领内操纵的是数据库)。在increaseMoney()要领前加了@Transcational注解,声名这个要领是带有事宜的。事宜能担保同组的SQL要么同时乐成,要么同时失败。讲原理,假如没有报错的话,应该每个线程都对money值举办+1。从理论上来说,功效应该是1000的才对。

(参考我之前写过的Spring事宜:一文带你看懂Spring事宜!)

按照上面的说明,我猜疑是提问者没测试好(hhhh,逃),于是我也跑去测试了一下,发明是以提问者的方法来行使是真的有题目。

起首贴一下我的测试代码:

  1. @RestController 
  2. public class EmployeeController { 
  3.  
  4.     @Autowired 
  5.     private EmployeeService employeeService; 
  6.  
  7.     @RequestMapping("/add") 
  8.     public void addEmployee() { 
  9.         for (int i = 0; i < 1000; i++) { 
  10.             new Thread(() -> employeeService.addEmployee()).start(); 
  11.         } 
  12.     } 
  13.  
  14.  
  15.  
  16. @Service 
  17. public class EmployeeService { 
  18.  
  19.     @Autowired 
  20.     private EmployeeRepository employeeRepository; 
  21.  
  22.  
  23.     @Transactional 
  24.     public synchronized void addEmployee() { 
  25.  
  26.         // 查出ID为8的记录,然后每次将年数增进一 
  27.         Employee employee = employeeRepository.getOne(8); 
  28.         System.out.println(employee); 
  29.         Integer age = employee.getAge(); 
  30.         employee.setAge(age + 1); 
  31.  
  32.         employeeRepository.save(employee); 
  33.     } 
  34.  

简朴地打印了每次拿到的employee值,而且拿到了SQL执行的次序,如下(贴出小部门):

从打印的环境我们可以得出:多线程环境下并没有串行执行addEmployee()要领。这就导致对统一个值做一再的修改,以是最终的数值比1000要少。

二、图解呈现的缘故起因

发明并不是同步执行的,于是我就猜疑synchronized要害字和Spring必定有点斗嘴。于是按照这两个要害字搜了一下,找到了题目地址。

(编辑:河北网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读