synchronized底层原理解析

sychronized底层原理探秘

Synchronized作用:

官方解释:同步方法支持一种简单的策略来防止线程干扰和内存一致性错误:如果一个对象对多个线程可见,则对该对象变量的所有读取或写入都是通过同步方法完成的。
一句话总结出Synchronized的作用:
  能够保证在同一时刻最多只有一个线程执行该段代码,以达到保证并发安全的效果

synchronized的底层原理及其实现:

代码结合模型分析的更加透彻

场景:模拟双十一秒杀活动,数据库一共有5条数据,使用JMeter模拟30个线程同时访问以下程序,结果是什么


@Service
public class SychronizedTest {



	private  static Object object=new Object();


	public String decStockNoLock(){
		Integer stock ;
		synchronized (object){
		List<Map> result=jdbcTemplate.query("select stock from shop_order where id=10");
		if(result==null||(stock=(Integer)result.get(0).get("stock"))<=0){
			logger.info("下单失败,已经没有库存了");
			return "下单失败,已经没有库存了";
		}
		stock--;
		jdbcTemplate.update("update shop_order set stock=? where stock=1",stock);
		logger.info("下单成功,当前剩余产品数------>"+stock);
		}
		return "下单成功,当前剩余产品数------>"+stock;
	}
}

假设我们没有加synchronized关键字修饰代码块,那么这30个线程都会下单成功。如果加了synchronized后则只有几个线程会下单成功。为什么呢?

三条了逻辑操作语句如下:

1  List<Map> result=jdbcTemplate.query("select stock from shop_order where id=10");
2  stock--;
3  jdbcTemplate.update("update shop_order set stock=? where stock=1",stock);

不加锁:
先上图:

最开始主存里面的stack=5,三个线程获取到了这个stack变量,将他们拷贝到自己的工作内存中,对stack进行stack–操作,此时三个线程将自己工作内存的stack变量通过原子操作store和write同步到主内存.此时bug就发生了,明明三个线程都对stack变量进行了stack–操作,此时的stack应该是2才对。

上述方法不是同步方法,可能线程1执行了第二行逻辑代码,线程2执行了第三行逻辑代码,线程3又执行了第一行逻辑代码,那么就会导致数据的不一致性。

加锁:
给需要同步的代码块加上synchronized关键字就可以避免这一现象,为什么呢?如果是官方给的解释,那等于值告诉我们是什么,没告诉我们为什么。

先从Java内存模型分析:
还是先上图:
在这里插入图片描述

首先线程1获取到了Object对象的锁,此时JVM会通过lock原子操作给Object对象加一个锁。其他的线程对这个对象无法读,无法写,其他的线程进行阻塞,进入阻塞队列。直到线程1,做完了按照原子操作的顺序完成操作,释放锁。然后会唤醒其他因为等待这个锁释放而进入阻塞队列的线程。(注意:是等待这个锁而进入阻塞队列的线程,而不是其它阻塞队列的线程)

再从字节码的执行分析:
还是先上图:
在这里插入图片描述

我们分析了Java执行的字节码文件,发现在执行逻辑的前面有一个monitorenter在执行逻辑的后面有一个monitorenterexit.如上图,每一个对象在创建的时候,JVM就会给它匹配一个Monitor对象。
解释了monitor对象,我们就来解释moniter的是实现原理:
JVM内置锁通过synchronized的使用,通过内置对象Monitor(监视器锁)实现,基于进入和退出Monitor对象实现方法和代码块同步,监视器的锁的实现依赖操作系统的底层Mutex Lock(互斥锁)来实现,是一个重量级锁,性能较低。
原理如下图:在这里插入图片描述

通过以上2中方法分析,应该已经很清楚了synchronized的底层原理

synchronized关键字是用于实现线程同步的重要关键字。它的底层原理涉及到对象的内部锁机制。当一个线程进入一个synchronized代码块或方法时,它会尝试获取该对象的内部锁。如果没有其他线程持有该锁,那么该线程就会成功获取到锁并执行代码块或方法。如果有其他线程已经持有了该锁,那么该线程就会被阻塞,直到其他线程释放了锁。这样可以确保在同一时刻只有一个线程执行被synchronized修饰的代码块或方法,从而保证了并发安全性。 在底层,Java虚拟机使用了monitor对象来实现synchronized关键字。每个对象都有一个与之关联的monitor对象,用于实现锁的机制。当线程获取到一个对象的锁后,它会进入monitor对象的锁定状态,其他线程将无法进入该对象的synchronized代码块或方法,直到拥有锁的线程释放了锁。当线程释放锁时,它会将锁的状态设置为可用,然后通知等待的线程有机会获取锁。这种基于monitor对象的锁机制确保了线程之间的互斥和同步。 <span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [深入理解synchronized底层原理,一篇文章就够了!](https://blog.csdn.net/qq_36934826/article/details/95978700)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Synchronized的底层实现原理(原理解析,面试必备)](https://blog.csdn.net/weixin_42460087/article/details/126474481)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值