Java并发(二)——Lock

作者: 贪婪的君子 | 来源:发表于2017-05-12 17:21 被阅读45次

    这把锁(Lock),只有我有钥匙。

    线程的活跃度(Liveness


    一个并行应用程序的及时执行能力被称为它的活跃度(liveness)。

    死锁(DeadLock

    在计算机科学领域中,有一个经典问题——哲学家就餐问题,这个问题可以表述为:
    五位哲学家围着一张桌子就餐,每两人之间都放有一直叉子(共有五个叉子),而哲学家就餐时需要同时使用两个叉子(一共需要十只叉子)。
    而现在做出如下假设:
    五个哲学家同时拿起身旁的一支叉子,但是由于每人需要同时使用两只叉子才能就餐,因而没有人可以就餐。每个人拿着自己的叉子坚持不放,同时又向身边的人索要叉子,此时就出现了一个死循环,因为没有人肯放下手中的叉子,所以没有人能得到除手中叉子以外的第二支叉子
    这也就是所谓的死锁(DeadLock)。

    死锁

    当程序都只运行了forkCount--后,继续推进时发现在while判断中所有的线程都会等待,直到申请到资源才能继续推进。

    死锁是指两个或两个以上的线程永远被阻塞,一直等待对方的资源。
    在多线程中,存在死锁情况的程序中,死锁发生的时间、是否会发生是不能确定的(在多线程中,程序是交叉执行的)。

    活锁(LiveLock

    还是哲学家就餐问题:
    假设哲学家就餐时做两件事情:1. 思考,2. 吃饭
    当在哲学家都不思考,将进入吃饭状态时,会发生死锁。然而如果其中一人开始思考,放下手中的叉子,那么对应的就有一人可以拿起第二支叉子,处于吃饭状态。
    按照该思路可以假设规定当哲学家等待另一只餐叉超过五分钟后就放下自己手里的那一只餐叉,并且再等五分钟后进行下一次尝试,如此一来就避免了死锁的发生。但是依旧还有活锁的情况。
    活锁的假设:
    五位哲学家同时拿起左边的餐叉,那么这些哲学家就会等待五分钟,同时放下手中的餐叉,再等五分钟,又同时拿起这些餐叉,如此循环,即发生了活锁(LiveLock)

    活锁01

    所有线程都在执行了第一条判断语句的内容后被中断。

    活锁02

    当所有线程都已经执行完拿起左叉的动作后,程序继续推进时所有的线程仅执行判断是否有右叉,当所有线程都执行完该判断时,继续执行放左叉动作。往复循环,形成活锁。

    一个线程常常处于响应另一个线程的动作,如果其他线程也常常处于该线程的动作,那么就可能出现活锁。
    程序无法进一步执行这一点与死锁相同。然而不同的是,线程是不会阻塞的,他们只是会忙于应对彼此的恢复工作。
    思考现实中两人在走廊相遇时可能会发生的一种“默契”。

    饥饿(Starvation

    对哲学家做出如下假设:
    其中两位哲学家霸占叉子,剩余三名哲学家和一把叉子,这三名哲学家一直等待吃饭状态的两名哲学家放下叉子,时间一长,剩下的三位哲学家得不到叉子,无法吃饭,变得饥饿(Starvation)。
    假设这三名哲学家已经很久没吃饭,又由于得不到叉子,时间一久,就饿死了。

    依旧是前文活锁的程序,但此时有一线程在判断完右叉不存在时,紧接着做出放下左叉的动作,然后下一个线程就可以得到右叉继续推进,但其他的线程却因为得不到叉子,出现了饿线程死。

    线程不能获得定期访问共享资源,于是无法继续执行

    小结

    有关上述问题的解决方案很多,但这里只做问题的说明,有关解决方案,后面会逐步介绍。

    相关文章

      网友评论

      • 2299eb13c5b7:没有代码不好想象!多线程一直都有些模糊,平时用很少写源码!
        贪婪的君子:有代码也不容易想象,不如看看更新之后加上的图

      本文标题:Java并发(二)——Lock

      本文链接:https://www.haomeiwen.com/subject/ewqtxxtx.html