两个或两个以上的进程在执行过程中,因争夺资源而造成的一种相互等待的现象,若无外力作用,他们都将无法推进下去,陷入死循环
上面介绍了死锁的四个必要条件, 只要破坏了四个必要条件中的任意一个条件, 死锁就不会发生了.
1.打破互斥条件
就是允许进程同时访问某些资源. 但是, 有的资源不允许被同时访问, 这是由资源本身的属性决定的. 所以, 这种办法并无使用价值
2.打破禁止抢占
就是允许进程强行从占有者那里夺取资源. 当一个进程已占有了某些资源, 有申请新的资源, 但不能立即被满足时, 必须释放所占有的全部资源, 以后再重新申请. 这种预防思索的方法实现起来困难, 会降低系统性能.
3.打破持有和等待状态
可以实行资源预先分配策略. 即进程在运行前一次性地向系统申请它所需要的全部资源. 如果某个进程所需的全部资源得不到满足, 则不分配任何资源, 此进程暂不运行. 只有当系统能够满足当前进程的全部资源需求时, 才一次性地将所申请的资源全部分配给该进程. 由于运行的进程已占有了它所需的全部资源, 所以不会发生占有资源又申请资源的现象, 因此不会发生死锁. 但是, 这种策略有如下缺点:
4.打破循环等待
实行资源有序分配策略. 即将资源事先编号, 按号分配, 进程对资源的请求必须按资源序号递增的舒徐提出. 这样就不会差生环路, 从而预防了死锁. 这种策略与前面的策略相比, 资源的利用率和系统吞吐量都有很大提高, 但是也存在以下缺点:
1.加锁顺序
当多个线程需要相同的一些锁, 但是按照不同的顺序加锁, 死锁就很容易发生.
如果能确保所有的县城都是按照相同的顺序获得锁, 那么死锁就不会发生了.
2.加锁时限
可以避免死锁的方法是在尝试获取锁的时候加一个超时时间, 线程可以在获取锁超时以后主动释放之前已经获得的所有的锁. 通过这种方式, 也可以很有效的避免死锁
使用Lock接口的 tryLock(long, TimeUnit) 方法, 当获取锁超时时主动释放之前已经获得的所有锁.
4.通过信号量控制
信号量可以控制资源能被多少线程访问, 指定只能被一个线程访问时, 就做到了类似锁的操作.
Java 中的 Semaphore 类可以做到信号量控制, 通过 tryAcquire(int, long, TimeUnit) 方法获取信号量许可, 超时则为其他线程占用, 释放所有已获取的许可. 代码如下:
1.使用 JConsole 命令
通过JDK带的 java监视和管理控制台 工具, 可以查看java进程运行情况
在cmd运行 jconsole 打开
2.使用 jstack 命令
先通过 jps 命令查看 java进程的id
然后通过 jstack id 查看该进程的堆栈情况及错误信息