多线程基础(四)之死锁

作者: 承香墨影 | 来源:发表于2017-03-09 23:58 被阅读25次

    版权声明:

    本账号发布文章均来自公众号,承香墨影(cxmyDev),版权归承香墨影所有。

    允许有条件转载,转载请附带底部二维码。

    一、前言

    在Java中,如果使用到多线程的技术,除了要考虑同步锁之外,还需要考虑,在使用锁的过程中,可不可能造成死锁的情况。本篇就死锁的情况进行一个简单的讲解,让大家在使用的过程中,了然于胸。

    二、什么是死锁?

    先看看百度百科的解释:

    所谓死锁:是指两个或两个以上的进程在执行过程中,由于竞争资源或由彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。彼此称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

    在Java线程的实现中,死锁是一个非常经典和常见的问题,当业务复杂度低的时候,一般都是可以避免的,但是一旦业务复杂度增大,就可能导致多个线程在执行的过程中,等待了根本不可能被释放的锁,从而导致后面所有的任务都被挂起无法得到执行。这样的情况下,程序将无法继续执行,会出现线程“假死”的情况。

    三、为什么会出现死锁

    死锁其实就是一种Bug,在程序设计的时候,只要避免在双方互相持有对方的锁资源的情况,就是不要有互相等待的情况。一般而言就不会出现死锁。

    举个例子:

    小明说,如果小新买了梨,那我也买点苹果。

    小新说,如果小明买苹果了,那我就买点梨。

    结果可想而知,当自己的业务需要受到对方影响的情况下,如果这种影响说是相互互斥而不存在例外情况的话,就会出现死锁,这个例子中,小明和小新永远都不会去买自己需要的水果。

    那么死锁可不可怕,其实说严重也严重,但是一般而言,因为太严重了,通常出现死锁之后,业务无法继续下去,是可以被开发人员感知到的,而得到处理。

    四、出现死锁如何解决?

    出现死锁的情况下,只需要我们dump线程来查看到底是哪个些线程出现了死锁的情况。

    其实JDK自带了命令行工具来帮助我们dump出线程的堆栈。

    1. 首先使用jps,找到线程的PID。
    1. 再通过jstack获取制定PIC的ThreadDump。

    它们的使用方式非常的简单:

    • jps,可以查询到当前被挂起的线程的pid。
    • jstack -l <pid>,可以查询到指定pid的情况。

    主要是找关键字:“java.lang.Thread.State:BLOCKED”,如果多个线程出现了的状态都是BLOCKED,那么可能就是造成死锁的原因。

    五、立几个消灭死锁的军规

    既然死锁是非常严重的Bug,会造成多线程互相等待,从而影响业务。那么我们立几条消灭死锁的军规,在开发中严格准照,一般就可以避免大多数可能被死锁的情况。

    1. 避免一个线程同时获取多个锁。单一职责思路,一个线程只干一件事情。
    1. 避免一个线程在锁内同时占用多个资源。单一职责也是相互的。
    1. 尝试使用lock.tryLock(timeout)来替代使用的同步锁。这种定时锁会有超时机制,保证了在出现可能死锁的情况下,依然有例外情况下可以跳出控制。
    1. 对于数据库锁,加锁和解锁必须在一个数据库连接中,否则会出现解锁失败的情况。这个不难理解,不是同一个数据库连接,解锁的就已经不是之前加锁的锁了。
    公众号二维码.jpg

    相关文章

      网友评论

        本文标题:多线程基础(四)之死锁

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