两层 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 的外面,它会直接返回,正好确实不需要写存档了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值