死锁相关问题

什么是死锁

两个或两个以上的进程在执行过程中,因争夺资源而造成的一种相互等待的现象,若无外力作用,他们都将无法推进下去,陷入死循环

产生死锁的必要条件

  1. 互斥. 一个资源每次只能被一个线程使用
  2. 禁止抢占. 线程已获得的资源, 在未使用完之前, 不能强行剥夺
  3. 持有和等待. 一个线程因请求资源而阻塞时, 对已获得的资源保持不放
  4. 循环等待. 系列进程互相持有其他进程所需要的资源, 造成互相等待的局面

死锁的预防

上面介绍了死锁的四个必要条件, 只要破坏了四个必要条件中的任意一个条件, 死锁就不会发生了.

1.打破互斥条件

就是允许进程同时访问某些资源. 但是, 有的资源不允许被同时访问, 这是由资源本身的属性决定的. 所以, 这种办法并无使用价值

2.打破禁止抢占

就是允许进程强行从占有者那里夺取资源. 当一个进程已占有了某些资源, 有申请新的资源, 但不能立即被满足时, 必须释放所占有的全部资源, 以后再重新申请. 这种预防思索的方法实现起来困难, 会降低系统性能.

3.打破持有和等待状态

可以实行资源预先分配策略. 即进程在运行前一次性地向系统申请它所需要的全部资源. 如果某个进程所需的全部资源得不到满足, 则不分配任何资源, 此进程暂不运行. 只有当系统能够满足当前进程的全部资源需求时, 才一次性地将所申请的资源全部分配给该进程. 由于运行的进程已占有了它所需的全部资源, 所以不会发生占有资源又申请资源的现象, 因此不会发生死锁. 但是, 这种策略有如下缺点:

  1. 许多情况下, 一个进程在执行之前并不可能知道它所需要的全部资源. 这是由于进程执行时是动态的, 不可预测的.
  2. 资源利用率低. 无论所分资源何时用到, 一个进程要占有全部资源后才能执行. 即使有些资源最后才被该进程用到一次, 但该进程在生存期一直占有它, 造成长期占着不用的状况. 显然是一种极大的资源浪费.
  3. 降低了进程的并发性. 因为资源有限, 又加上存在浪费, 能分配到需要的全部资源的进程个数必然少了

4.打破循环等待

实行资源有序分配策略. 即将资源事先编号, 按号分配, 进程对资源的请求必须按资源序号递增的舒徐提出. 这样就不会差生环路, 从而预防了死锁. 这种策略与前面的策略相比, 资源的利用率和系统吞吐量都有很大提高, 但是也存在以下缺点:

  1. 限制了进程对资源的请求, 同时给系统中所有资源编号也是件困难事, 增加了系统开销.
  2. 为了遵循按编号申请的次序, 暂不使用的资源也需要提前申请, 增加了进程对资源的占用时间.

Java中死锁的避免

1.加锁顺序

当多个线程需要相同的一些锁, 但是按照不同的顺序加锁, 死锁就很容易发生.

如果能确保所有的县城都是按照相同的顺序获得锁, 那么死锁就不会发生了.

2.加锁时限

可以避免死锁的方法是在尝试获取锁的时候加一个超时时间, 线程可以在获取锁超时以后主动释放之前已经获得的所有的锁. 通过这种方式, 也可以很有效的避免死锁

使用Lock接口的 tryLock(long, TimeUnit) 方法, 当获取锁超时时主动释放之前已经获得的所有锁.

4.通过信号量控制

信号量可以控制资源能被多少线程访问, 指定只能被一个线程访问时, 就做到了类似锁的操作.

Java 中的 Semaphore 类可以做到信号量控制, 通过 tryAcquire(int, long, TimeUnit) 方法获取信号量许可, 超时则为其他线程占用, 释放所有已获取的许可. 代码如下:

死锁相关问题

Java定位死锁

1.使用 JConsole 命令

通过JDK带的 java监视和管理控制台 工具, 可以查看java进程运行情况

在cmd运行 jconsole 打开

2.使用 jstack 命令

先通过 jps 命令查看 java进程的id

然后通过 jstack id 查看该进程的堆栈情况及错误信息

订阅评论
提醒
guest
0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请发表评论。x