两层 if 防止同步问题

最近在阅读 weblech 的源代码的时候,发现一个写法有点意思。

public void saveCheckpoint()
    {
        SpiderConfig config = SpiderConfigInit.getSpiderConfigInit().getSingleSpiderConfig();
        long intervalMillis = 1000 * config.getCheckpointInterval();
        if(System.currentTimeMillis() - lastCheckpoint > intervalMillis)
        {
            synchronized(saveObj)
            {
                if(System.currentTimeMillis() - lastCheckpoint > intervalMillis) 
                {
                    writeCheckpoint(saveObj,saveFileName);
                    lastCheckpoint = System.currentTimeMillis();
                }
            }
        }
    }

这个函数位于一个线程类的内部,用来完成定时存档工作。它有两层 if 结构,中间有一个同步的操作。

隐约记得之前在《UNIX 环境高级编程》一书中看到过类似的用法,所以这里很快就知道了为什么这么写。

分析的思路如下:

假设结构为 if{synchronized}的结构,则可能在两个线程都进入if后,只有一个线程能进入锁并进行处理,而这个线程可能做了某些事,使得if条件不成立,但这时另一个线程已经通过了if,但这是编程人员在逻辑上不允许的,因为程序员应该保证每一步所产生的影响在可控范围内,否则,程序的逻辑则是模糊的,其运行的结果是无法预计的。所以,不可以为这个逻辑结构,除非你确定两个线程的操作对于再次进入 if 是没有影响的。


再假设,当结构为synchronized{if}的结构时会怎样呢?这其实很明显,如果一开始就同步,这会让不满足条件的线程耗费不必要的时间花在等待锁上,这样程序的效率就低了一点,所以要先判断它是否满足条件。


综上,所以结构是 if {synchronized if {}} 的结构。

我们再从正面来分析一下,这样写的好处。当存在多个线程会调用这个函数时,就会有线程进入最里层的 if ,记为 A,而还有线程卡在最外层的 if  的外面进不来。当A写存档之后,此时,正确的逻辑应该是其它的线程在时间间隔内不再需要写存档。所以,它会更改 lastCheckpoint 这个值,当卡在最外面的线程获得锁时,它又被卡在了最里面一个 if 的外面,它会直接返回,正好确实不需要写存档了。

在不同场景下有不同同步两个地图缩放和位置的方法。在 Echarts 地图中,可通过以下方式实现内外层地图同步缩放和平移: ```javascript echarts.registerMap('Map', area); myEcharts = echarts.init(dom, null, { renderer: 'svg' }); // 每次渲染前都要还原地图,防止沿用前一次缩放拖拽 myEcharts.dispatchAction({ type: 'restore' }); myEcharts.setOption(getEchartsOptions(data, areaName)); myEcharts.on("georoam", function (params) { let option = myEcharts.getOption(); // 获得option对象 if (params.zoom != null && params.zoom != undefined) { // 捕捉到缩放时 option.geo[0].zoom = option.series[0].zoom; // 下层geo的缩放等级跟着上层的geo一起改变 option.geo[0].center = option.series[0].center; // 下层的geo的中心位置随着上层geo一起改变 option.geo[0].animationDurationUpdate = 0; // 防止地图缩放卡顿 option.series[0].animationDurationUpdate = 0; // 防止地图缩放卡顿 } else { // 捕捉到拖曳时 option.geo[0].center = option.series[0].center; // 下层的geo的中心位置随着上层geo一起改变 } myEcharts.setOption(option); // 设置option }); ``` 这段代码通过监听 `georoam` 事件,当发生缩放或拖拽时,改变相应地图的缩放等级和中心位置,从而实现内外层地图的同步[^2]。 另外,在使用 MapboxGL 开发时,若要实现两个地图之间的滑动和同步比较,可以创建两个 `div` 来承载地图: ```html <div id="comparison-container"> <div id="before" class="map"></div> <div id="after" class="map"></div> </div> ``` 通过这种方式可以为后续实现两个地图的同步缩放和位置调整提供基础[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值