Spring中的synchronized

synchronized简介

java中的关键字,在JVM层面上围绕着内部锁(intrinsic lock)或者监管锁(Monitor Lock)的实体建立的,Java利用锁机制实现线程同步的一种方式。

synchronized保证的特性

    1.原子性:synchronized依靠两个字节码指令monitorenter和monitorexit,可以保证被synchronized修饰的代码在同一时间只能被一个线程访问。

    2.可见性:JMM(Java内存模型)规定,内存主要分为主内存和工作内存两种,每个线程拥有不同的工作内存,线程工作时会从主内存中拷贝一份变量到工作内存中。代码执行后,有时工作内存中的变量无法及时刷新到主内存中,或者工作内存无法及时获取主内存的最新值,导致共享变量在不同线程间处于不可见性,由此JMM对synchronized做了2条规定:

        a.线程解锁前,必须把变量的最新值刷新到主内存中。

        b.线程加锁时,先清空工作内存中的变量值,从主内存中重新获取最新值到工作内存中。

    3.有序性:有时候编译器和处理器为了提升代码效率,会进行指令重排序,但是as-if-serial规定无论怎么重排序,单线程程序的执行结果都不能被改变,而synchronized保证了被修饰的程序在同一时间内只能被同一线程访问,所以其也算是保证了有序性,但synchronized实际上并不是禁止了被修饰的代码指令重排序。
参考:CSDN博主「纯洁的小魔鬼」
原文链接:https://blog.csdn.net/xyy1028/article/details/106042888

正确使用方式示例

Spring中的synchronized容易出现不生效的情况,比如:在controller层加事物注解,内部代码块中含synchronized。

正确使用方式应当是:同步代码块在事物之前开启

在controller层加锁

@RequestMapping(value = "/purchase")
public synchronized String purchase(){
     return syncXyUserService.purchase();
}

在SyncXyUserService类上加@Transactional注解

​
public String purchase() {
        String msg = "";
                try{
                    Product product = productDao.findById(1L).orElse(null);
                    Integer leave = product.getLeave();
                    if(leave == 0){
                        msg = Thread.currentThread().getName() + ":购买失败";
                        log.error(Thread.currentThread().getName() + ":购买失败");
                    }else{
                        leave = leave - 1;
                        product.setLeave(leave);
                        productDao.update(product,true);
                        msg = Thread.currentThread().getName() + ":购买成功,剩余" + leave;
                        log.info(Thread.currentThread().getName() + ":购买成功,剩余" + leave);
                    }
                }catch (Exception e){
                    log.error("程序出错啦");
                }finally {
                }
            return msg;
}

​

为什么先调用@Transactional再调用synchronized会出现问题?

此处原文链接:https://blog.csdn.net/Rambo_Yang/article/details/119885524

1)事务开启在同步代码块之前
2)事务是 Spring 的 AOP 开启的,进入方法前,AOP 就开启了事务
3)事务开启以后才进入方法,再进入同步代码块加锁
4)当同步方法执行结束后,释放锁并提交事物(问题就出现在这里:如果在释放锁和提交事物之间有其它的线程请求,那么处理后的数据没有被提交,导致 synchronized 同步不生效的问题
 

Spring中的synchronized_第1张图片

你可能感兴趣的:(源码,spring,java,后端)