synchronized锁

现在集群,分布式,微服务这么火,基本上也不会有单机服务了,所以synchronized基本上就废了,但不影响我们再回忆一下他的一些思想,很多东西,万变不离其宗。

概念:

能够保证同一时刻最多只有一个线程执行该段代码,以达到保证并发安全的作用。

核心思想:

1、一个锁只能同时被一个线程获取,没拿到锁的线程必须等待
2、每个实例都对应自己的一把锁,不同实例的锁互不影响。
3、如果锁对象是*.class或者synchronized修饰静态方法时,所有对象其实是共用一把锁,这把锁也叫类锁。
4、锁住的方法如果抛出异常,JVM会自动释放锁。

性质

1、可重入
同一线程的外层函数获得锁后,内层函数可以直接再次获取该锁
好处:避免死锁,提高封装线性
2、不可中断
一旦这个锁被别人获得,那么我如果想获得这个锁,只能选择等待或者阻塞,直到别人释放了这个锁
相比Lock可中断,这个synchronized就是等到死。

原理

加锁和释放锁,其实就是操作内置锁,等价于lock的lock方法和unlock方法。
每个对象,都有一个对象头,对象头中可以存很多信息,其中有一个就是synchronized的信息。
javac test.java
javap -verbose test.class
对于加锁的,我们可以在反编译中看到两个指令,monitorenter和monitorexit。
这两个指令,就相当于Lock锁的lock方法和unlock方法。
monitor可以理解是个计数器,
计数器初始为0,0代表可以获取锁。
当一个线程获取锁,对应的就是执行monitorenter指令,计数器+1
同一个线程如果重入,就继续+1,多次重入就多次+1
当退出锁方法,对应的就是执行monitorexit指令,计数器-1
如果有重入的,那就退一个就-1,计数器减到0,就代表释放锁。
如果计数器不为0,那么其他线程尝试获取锁,就会获取不到。

synchronized保证可见性

我们知道线程之间的通信,是通过主内存通信的,而其实每个线程都有自己的本地变量的副本,加这一层就是为了快,类似于缓存,那只要是缓存,就会出现缓存不一致。
而使用了synchronized关键字后,就会无视这层缓存,比如一个对象被锁住,那么锁住后任何修改,都会直接写入主内存,所以不会出现线程的内存和主内存不一致的情况。
同样的,得到锁对象的时候,也是直接从主内存拿的。

synchronized缺点

1、效率低
锁不能人为释放,只能等执行完或者异常才能释放
Lock能解决这个问题(Lock可以设置超时时间,trylock方法)。
2、不灵活
相比读写锁,synchronized没分开读写,那读的时候也会加锁,是在没必要。

总结

单机服务,尽量少用synchronized
集群服务,禁止使用synchronized

虽然现在几乎不用synchronized了,但他的原理都是可以借鉴的,比如计数器+1的思路,解决可重入等等,其实包括现在的分布式锁,实现不一样,但说白了最终都是一样的,就是换个地方存计数器而已。redis分布式锁,相当于把计数器存在redis中,zookeeper分布式锁,相当于把计数器存在zookeeper中,数据库实现的,也是一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值