软件构造心得

前言
哈工大的软件构造期末考试题中,最有难度的往往就是多线程了。而很多同学包括我在内,也是上课听的很懂,但是实际操作中出现了很多问题。这篇博文就和大家一起捋捋期末考试题,看看技巧和入手的点在哪里。如有错误恳请指正。另附我们讨论出的陶神佬最终敲定的一份答案,欢迎大家一起来讨论,继续加大复习的深度!

2018年期末考题第二道大题

先po一下笔者认为的有风险的地方。
第一行的public,必然会引发表示泄露,而表示泄露从线程角度来看也是危险的,所以要将其改为private。加不加final修饰呢?我们发现,每一次调用removeSomelinesAndUnifyTitle方法都会进行一次大写的转换,而这个转换必然是会造成重新赋值的,所以不需要加上final修饰词修饰。
3、4行很明显露出了破绽,这种非匿名的方式把originLines留下来当作引用的风险,万一哪个糊涂蛋接手代码使用了这个那真的就会出带问题。所以两行合并成一行,细节就不说了。
第6行到第11行都应该被包括在一个锁内,那么用什么来锁,为什么缩到这个范围,可不可以再小呢?这些问题都是好问题。首先我们要明白会引发mutable类型线程不安全的原因就是其rep是可以被改变的,在我们的例子中就是所谓的lines是可以被改变的,因为共享内存的意义就是只要值不改变怎么顺序操作都不会彼此影响,但是数值一旦改变就会出现连锁问题(例子数不胜数)。那么我们就要保护pf,所以我们就最简单的方法,用pf上锁,内部修改没完事谁也别想得到pf锁。然后,范围是哪里呢,我们就要看在那块开始会影响到修改,iter那部分需要包进来吗?需要,因为如果我们不包,拿下来一个iter,另一个线程就有可能进行pf的修改,进而我们这个线程的pf的iterator再循环就会出索引上的问题 (问题很大,会触发异常,详情参见煊煊的源码分析博客Iterator源码分析,ArrayList源码分析,分析的非常透彻👍);那么removw要不要包,那肯定,如果不包进来也是会在要remove之前被其他remove影响。touppercase包不包?如果包了那可真就“达到下限了”,我们发现即使有先后,但是由于touppercase只会被影响一次,而且不会体现在结果上,所以并没有什么问题出现。所以就得到了最终范围。
stringbuilder和stringbuffer可换可不换,最好不换,因为不会造成线程问题,且效率更高。
16、17行,我们要使用pf锁包起来。有同学可能死脑筋:“老师明明说了只看不改不用加锁的?0-0”,诚然,但是我要说,这就和内卷效应和剧场效应一样,你大家都只看不碰,谁都没问题;一旦有一个人懂了歪心思,那么大家就都做不到线程安全了。这个tostring也是一个道理,假设说我们不加锁,在某一次调用tostring的for循环的某一个位置插进去一个remove操作把pf改掉了,那么很明显我们想得到的就不是我们所期待的tostring了。
本题心得
关注问题的根源是可变类型的修改,我们也要从被修改的rep进行入手。
范围是一点点找出来的,而不是一眼猜的。我们从变化rep的语句入手,不断地假想出来最坏的必须要锁的情况,进而一步步的扩大锁的范围。
剧场效应类似,大家都只看不碰没问题,一旦有一个人动了修改了rep,那无论其他是简单的observer还是什么,大家必须都要跟着加锁使得线程是安全的。要求我们具有整体观和大局观,辩证的看待线程
局部变量的是安全的,多线程波及不到的。在大脑中一定要形成空间意识,在大脑中就将栈和堆分开
2019年最后一道大题第二问
值得注意的是他想让我们“指出如何修改ConcreteParkingField、Lot、Car、ParkingThread 的代码”
(虽然第一问不是我们要讲的,但是其实是有三个位置,第一个是implements runnable,第二个是sleep应该try catch ,第三个是parking的try catch,sleep那个点很细节,感谢陶老指正

先po一下笔者认为的有风险的地方。
Lot,Car本身是immutable的,不存在线程危险。
对于ConcreteParkingField,我们首先的保证getOneFreeLot这个东西是安全的。如果这个东西本身不是安全的,那么在上面的代码的第11行就会出现你实际上搞回来一个数字,但是这个数字同时也被别的线程抢走了的情况。而这个方法没有给i相应的具体实现,所以我们只能把这个方法的signatrue加上synchronized。
回到ParkingThead代码上来,我们看到实际上它的逻辑就是尝试停车,如果没有车位,那么久sleep等待。我们还是按照惯例把切入点放到rep修改上,追踪到了第1行,开始上锁。可能被想到的一种解法就是把第11行道第17行(当前的),都包到锁里面。因为我们要避免先找到一个freelot之后却被另一线程抢停车导致脱离预期的情况,虽然这样有可能会因为sleep锁住很久,但是如果我们选择上锁,就只能这样了,但这样其实并不对(经沈哥指正,因为这样会使得一个线程把锁攥在手里然后因为没有停车位疯狂sleep,直到碰巧在下一次循环开始的时候拿到了锁,这样效率可见的低,而且如果大概率死循环),但是也没办法。经涛哥指正,我们再次考虑会发现11行和17行的分离就是一个离谱的事,其实我们应该将11和17合并,即将17放到11下面,然后这两行上一个锁,这样就最佳了,但其实这样也会产生问题,因为只有在getfreelot不为-1的时候我们才能停车,也就是如果这样的话,会出现在pf.parking中出问题,所以更进一步的,我们应该加上一个if判断,这样就完美了
本题总结

  1. sleep不会交出来锁。带着锁sleep。
  2. 更优化的办法实际上是使用wait和notifyAll,让这个线程wait,然后交出来锁,别的线程停车完事再notify停车,但这个不是我们需要掌握的核心知识。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值