一个资源应该单独使用一把锁。
比如,一个对象中有多个共享资源,但有多个线程需要使用其中的不同资源
此时如果把对象整体作为一把锁,那并发就很低。
可以考虑,把每个共享资源都单独拆出来,分别上锁,这样每个线程都能各取所需,提高了并发度。
坏处是,可能导致线程死锁。
线程的代码是有限的,但由于某种原因,线程一直执行不完,称为线程的活跃性。
活跃性有三种原因:死锁、活锁、饥饿。
死锁
指两个或多个线程互相持有对方所需的资源,但又都很傲娇,不想先释放资源,喜欢被动等人主动,若没有外力的作用下它们将永远的进行冷阻塞状态下。也所以它们(也就是线程)是得战不到正确的结果的,资源得不到释放、资源利用率降低,还会导致新的死锁产生。
竞争不可抢占性资源会导致死锁
竞争可消耗资源引起的死锁
进程推进的顺序不当也会导致死锁
简而言之,死锁就是恶性循环中的线程同步问题
解决方法:
- 所以避免这样,咱们就破坏”请求和保持”的条件,想办法不要让他们那么贪心,自己有资源就不要去竞争那些不可占的资源
- 每个进程都指定唯一的编号,给他们按照一定的顺序进行加锁,时间限制,一定的时间之后就不么在等待了,放弃有时候也是更好地方法,放弃等待,放弃吧,是你的终究是你的,不是你的咱就莫强求,强扭的瓜解渴但不甜
- 银行家算法,利用算法对某时刻进行安全分析,必定会存在一个安全的序列
活锁
活锁是一个更加隐晦的问题,他比死锁更加复杂,也难以排查。
但又与死锁类似,它也是指多个线程独立互相等待其它线程释放它们自己本身所需资源的占有,这里没有所谓资源的争抢。活锁,线程并未阳寒,下们一直在尝试改变自身的状态,去试图执行任务,但任务总是失败。这就像在做无用功,实际没干什么事。
给大家举一个很简单的例子:
一座华丽的小破桥,两边都来了一辆马自达,都在希望对方先过,都在等,结果导致大家都没走。亏贼!
解决方法:
- 导致原因 重试机制不变,消息队列始终重试,吃饭始终谦让
- 以太网的指数退避算法
- 加入随机因素
- 增加随机的睡眠时间,将这样的两个线程错开执行,只要一方先运行完了,那么另一方也就能运行完
饥饿
饥饿其实也很好理解:一个或多个线程由于没有足够的资源而导致这个线程无法执行
出现饥饿可能是有其它线程优先于已持有了人家自己所需的资源正在运行了。当你还在问开始了吗? 人家已经在运行了,因此你一直处于无限的等待状态
所以饥饿是比死活锁更为普遍常见的问题例如: 过度保护锁机制、繁忙等待、优先级倒置等问题
咱们也同样来举一个易理解的例子:
一家餐厅,多个人在等待吃饭,系统按照短文件优先的策略排序,该策略具有平均等待时间短的优点。所以饭量小的先吃,这样的话就会出现这么一种情况,如果饭量小的人一直源源不断,那么饭量大的则将无限期地推迟进去吃饭,那么就会导致饥饿甚至于饿死
解决方法:
- 调整锁的优先级
- 采取公平的锁机制
- 以及避免过分的资源占有
欢乐的时光总是短暂的,又到时间讲拜拜,咱们下次再见咯!