00:00
好,各位同学,我们继续,那么接下来对于读写锁它的使用很简单,大家都已经一目了然了。这个说过了,所降级也强调过了,那么也就是我们说的可以降级邪所在写的时候可以降级为读索示范写索示范读索为什么这张图重要?Oracle公司JDK的源码为什么要怎么设计好?那么接下来我们就要给大家解释。他为什么要有所降级这种思想?那么请看一下欧尔公司对于可重入读写所的源码总结答。下面的源码呢,是摘自于官网啊,我们先看这个代码,听着杨哥讲,那么你要听不懂,后面的解释都有,所以说我们在这儿。遵循按照获取写索,获取读索,在释放写索的次序,写索能够降级成为毒索,不支持所升级。所以说在这块来吧,这是一个样例。
01:02
请看源码,他做了一个date缓存数据类,这有。这么三个定义的field的变量,第一个贝数据,第二个有个V修饰的cash value的这么一个布尔值,然后这是一个什么。读写所,那么接下来搂眼方法就一个,红对红,蓝对蓝,绿对绿,听杨哥分析和解释。首先。处理缓存数据的一个进程程序。先来读读一下这个缓存有没有,或者有没有更新啊,我们来。读,那么来这个时候默认大家请看这个值布尔值默认什么是负,负取个反什么意思啊。是摘if进来,红对红,那么我先来读吧,我要读的时候是不是要加读索,那么请这句话请看,假设这个缓存啊,现在是空的,我去读没有意义啊,所以说我要通知写的线程来写,那这个时候请看必须示范这个读索,在获取写索之前,我们前面是不是强调过。
02:09
你读所没有示范的话,写所是干不进去的。所以想要。获得一个写索,你必须先示范是吗?读索,所以说它这这个这个这个这三行,你可以把它理解为我先去看看缓存里面有没有数据。没有。读完了没有马上释放,毒所允许去修改,那么大家请看。我这儿。这么一个事儿。这个时候是邪锁。那么邪锁出。Final。这个加入写索某个线程来写了巴拉巴拉巴拉的各种对吧,业务逻辑写完了,那么请大家看这。State,因为另外一个线程可能会占用这个协索,并且改变这个状看在我们做这个业务之前。所以说请大家看。
03:03
他干了一件什么事之二?12是判断了两次啊。OK,有没有点像我们的双端检索的这种思想?它的意思什么?我虽然说拿到解锁了,但是怕我抢的过程当中已经有人改了,那么我们先看看这个cash value它是什么值,如果还是false false取法,那么我同一个线程。现在把这个date哒哒哒哒哒哒改成,比如说从55改成88,我这个数据修改了,现在最新的值就是88。Valid true,那么是不是从默认值的变为说明?我这个线程写完了,但是注意。请看下面所见,其通过占有独索在释放解索之前。那么他干什么呢?他是这么想的。从串到这儿,这一段代码之间,意思就是说这一个线程我已经写完了,我的数据是这个。
04:08
那么现在。我写完以后我马上。要去用我刚刚提交的新的数据,也就是我们刚才所说的88这个数字,我怕别人乱改。不能放出去,我马上获得读索,就说我写完以后,假设写进数据库,现在最新值啊,从55修改为88,那么我想马上读出来这个88,在88的这个基础上,我再进行修改,那么相当于说我这儿立刻又获得读所。相当于同一个线程从写索降级为读索可重入明白这个是支持的,然后翻译到你这写完了就告诉程序我修改缓存完活,但是修改完了以后写后读,写完了以后同一个线程马上要去读取,在我自己修改完的基础上,那么这个就是属于什么所降级从写索降为读,所写完了以后马上去读,那么这个时候。
05:06
相当于说。这把锁的只有权限还是在同一个线程,这那么大家请看我夹着读锁,我夹着读锁前面我们说过,当一个线程拿着读锁它没有读完的时候,其他写索是获取不到的,必须要等他读完。那么。得到这try use date,那么这有一个方法,这个date是不是刚刚被我从55改成88,那么还是这个线程写完以后马上就可以用88这个数据,那么OK。用完了finally再把毒所释放,你们再去改吧。那么。蓝色的是血,绿色的是毒,同一个线程写索变成毒索,立刻完成写后。读这样的所降级策略保证了数据的一致和安全,那反过来你不同意,你说我就不这么干。我想干别的。我这不加,按照我的习惯,写完了以后我再去读,好兄弟,你没有加在这儿,假设同一个线程在这儿,Final里再把写索示范搁到这儿,那么这一行代码是不是就没有没有在这儿了?你没有在这儿的过程当中,你只能在。
06:09
TRY这块对吧,你读的时候你再去加,可是中间这块的时候,你只要敢释放了这个写索马上有别的线程。去抢,那这个时候可能你的这个值88就被别人改成了1024啊,那么这个时候,哎呀。你本来想做的事。把它从55改成88,又在88读取到88这个基础上做你的事儿,结果现在你没有立刻。加毒所。没有写后立刻读,而是释放了写索,写完了以后,你准备想自己再来抢一次啊,你怎么能这么把本的就确定,还是你能够马上释放完邪锁以后,你马上有人抢到这个毒索呢?所以说不好意思啊,这种情况下有可能你释放完这个邪锁。你的想法是想马上又获得这个毒锁,但是有可能别人比你捷足仙丹又去抢到了这把锁,而且又把数据改了,从你7万的88改成了1024或者其他值啊,你这样是不是瞎子点灯白费了,白费功夫啊。OK,所以说必须。
07:16
要保证自己的业务,我写完以后我还想继续读,那么马上实现所降级,写完以后自己立刻获得读数,读完以后再真正示范,这是一套带走一题两面,OK,好,那么所以说上面的解析我们可以看。代码中我们生命于那个V的布尔型的变量,保证其可见性,默认值false OK,来了,接下来。首先获得锁,如果这个缓存不可用,则释放锁,获取写锁,那么首先红色这段假设缓存里面没数据呢?那。不用去费功夫。没有马上获得写锁,写点东西进去,OK,那么。在更改数据之前再检查一次这个值,我们有点类似于双端检索对吧,然后修改数据,那么就是这个date,比如说从55啊改成88,既然这个在置为戳,那么从force变为戳,说明有人动过了,然后在示范写索前立刻抢夺获取读所在示范就是在这一行我的全部写的业务逻辑完成了,但是我还要在我自己写完以后,我马上想接着读不放,那么所以说。
08:29
根本没有丢失,这把锁只是完成了锁将及从解锁到毒锁,还是我在我手上同一件衣服,左口袋到右口袋,还是你自己持有,那么这个时候缓存中的数据可用处理缓存中的数据,最后我在示范什么锁?读所用完了先写,然后再用,用完了再释放,那么这个过程就是一个完整的所降级过程,目的就是为了保证数据的可见性,OK,同一个线程写完了以后还想写完了以后再接着去读,再去做其他工作,你这个时候你千万不能释放锁,马上进行切换,从写索到读索完成锁降级,否则你只要一示放,有可能别人就先。
09:12
抢到了一把锁,又把数据改的面目全非,你这不就白费功夫了?OK,那么所以说一句话。同一个县城自己持有协锁。再去拿毒锁先本质啊,相当于重入锁,左口袋到右口袋,好吧,还是你拿着这个锁先写在读,写后立刻读,那么假设你要违背这个策略呢?那么就是你不在这加,你要在这儿加,OK,那么中间这块那麻烦了。有别人会把你改了,来,我们来看看。假设啊,你违背上面的正确流程,你非要头铁,你非要对着干,如果当前线程C在修改完这个当中没有获取读索,而是直接释放了写索,这句话的意思说没有绿色这条对吧?你写完了就finally写索示范这句话没了,那么弟兄们你晓得呢?
10:02
另外一个县城D。马上获得写锁,并又修改了数据,从88改成1024,那么C线城市无法感知到数据,已经被修改了的数据容易出现错乱,那么假设地改完了以后,C想当然的说认为我释放写锁,我马上可以获得独锁。麻烦了。在你想当然这一片刻,D这个线程进来把它改了,假设顺利,你这个C又抢到了,结果发现你的数据已经从88被D改成1024 OK,所以说。我们这儿。只能是线程C在示范写索之前获取读索,那么线程D在获取写索时将被阻塞,就是C。还没有读完的时候,那个D不要去乱改,直到线程C完成数据处理过程,读完了,释放了读索,那么这样D才可以获得,那么这样就可以保证返回的数据是C本次更新的数据,这种机制就是专门为缓存设计的,尤其要注意,同一个线程写完了以后,我还想继续读,你可千万不要示范所,一定要从写索变成读锁,用锁降级。
11:13
替代示范所,否则你的数据一定会出错,这个就是我们所降级的策略和思想以及目的,大家一定要掌握这个思想非常重要。
我来说两句