zoukankan      html  css  js  c++  java
  • Synchronized 失效原因

    Synchronized 同步出现失效

    Synchronized ,大家都知道这个是Java 提供的一种原子性内置锁,其实现原理是通过获取对象的监视器monitor进行来实现同步的,只有当线程获取到对象monitor才能继续执行,否则该线程进行阻塞(等待)。

    示例:

    public class DemoServiceImpl {  
    
        @Autowired    
        private DemoDao demoDao;    
        
        // 根据id获取序列号,获取完之后进行 + 1        
        @Transactional    
        public synchronized String getSn(Long id) {
               DemoSn sn = demoDao.getSnById(id);       
               sn.setSn(sn.getSn() + 1);       
               demoDao.update(sn);         
               return sn.getSn().toString();    
        }    
     }
    
    

    描述一下代码示例: 该方法涉及++ 1 ,当如果多个线程进行调用该方法时,会出现数据安全性问题,所以我在这里进行加了 Synchronized, 保证该方法的每次执行只能允许一个线程进来。

    本以为这里加了 Synchronized, 就是线程安全了,但是经过测试之后发现,这里同步锁并没有起作用,多个线程进行调用该方法时,还是出现返回的 值重复。

    Synchronized 失效原因:
    先简单介绍一下Spring @Transactional执行原理: @Transactional 注解是Spring 提供来进行控制事务的注解,当注解标明在方法上时, 则会对 该方法进行做AOP 增强(动态代理),然后在方法执行前,开启事务,执行后提交事务。

    如果上述示例方法只添加了 Synchronized, 并没有标明@Transactional, 因为加了同步锁,所以getSn() 一次只能允许一个线程进入, 执行过程:

    A(线程): DemoServiceImpl#getSn() > B(线程): DemoServiceImpl#getSn()
    

    如果上述示例方法添加了 Synchronized,并标明@Transactional 线程的执行过程:

    A(线程): Spring begins transactional > DemoServiceImpl#getSn() > Spring commits transactional
    B(线程): Spring begins transactional > DemoServiceImpl#getSn() > Spring commits transactional 
    
    

    这里看着是没有问题

    开启事务 -> 执行方法体 -> 提交事务

    但是这里也恰恰是出现Synchronized 失效的关键

    Synchronized 失效关键原因:是因为Synchronized锁定的是当前调用方法对象,而Spring AOP 处理事务会进行生成一个代理对象,并在代理对象执行方法前的事务开启,方法执行完的事务提交,所以说,事务的开启和提交并不是在 Synchronized 锁定的范围内。出现同步锁失效的原因是:当A(线程) 执行完getSn()方法,会进行释放同步锁,去做提交事务,但在A(线程)还没有提交完事务之前,B(线程)进行执行getSn() 方法,执行完毕之后和A(线程)一起提交事务, 这时候就会出现线程安全问题。



    作者:技术基地
    链接:https://www.jianshu.com/p/3e30cc705f09
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    我不会用 Triton 系列:Model Warmup 的使用
    我不会用 Triton 系列:Python Backend 的使用
    C++11 Memory Order
    我不会用 Triton 系列:Triton 搭建 ensemble 过程记录
    我不会用 Triton 系列:Stateful Model 学习笔记
    CUDA 概念汇总
    字符串的扩展
    梦学谷会员管理系统
    普希金-假如生活欺骗了你
    变量的解构赋值
  • 原文地址:https://www.cnblogs.com/eryun/p/12034381.html
Copyright © 2011-2022 走看看