在安全性与活跃性之间一般存在着某种制衡,咱们使用加锁机制来确保线程安全,但若是过分地使用加锁,则可能致使“锁顺序死锁”。一样,咱们使用线程池和信号量来限制对资源的使用,但这些被限制的行为可能会致使资源死锁。安全
锁顺序死锁:两个线程试图以不一样的顺序来得到相同的锁,若是按照相同的顺序来请求锁,那么就不会出现循环的加锁依赖性,所以也就不会产生死锁。 在制定锁的顺序时,可使用System.identityHashCode方法,该方法返回有Object.hashCode返回的值,经过比较大小等方法定义锁的顺序。在某些状况下,两个对象可能拥有相同的散列值,此时必须经过某种方法来决定锁的顺序,而这可能会从新引入死锁,为了不这种状况,可使用“加时赛”锁,在得到两个对象的锁以前,首先得到这个加时赛锁,从而保证每次只有一个线程以未知的顺序得到这两个锁。并发
在协做对象之间发生的死锁 若是在持有锁的状况下调用某个外部方法,那么就须要警戒在协做对象之间发生死锁。 若是在持有锁时调用某个外部方法,那么将出现活跃性问题,在这个外部方法中可能会得到其余锁(这可能会产生死锁),或者阻塞时间过长,致使其余线程没法及时得到当前被持有的锁。ide
开放调用 若是在调用某个方法时不须要持有锁,那么这种调用被称为开放调用。 在程序中应尽可能使用开放调用。与那些在持有锁时调用外部方法的程序相比,更易于对依赖于开放调用的程序进行死锁分析。线程
资源死锁设计
引起饥饿的最多见资源就是CPU时钟周期,若是在Java应用程序中对线程的优先级使用不当,或者在持有锁时执行一些没法结束的结构(例如无限循环,或者无限制地等待某个资源),那么也可能致使饥饿,由于其余须要这个锁的线程将没法获得它。线程优先级并非一种直观的机制,而经过修改线程优先级所带来的效果一般也不明显。当提升某个线程的优先级时,可能不会起到任何做用,或者也可能使得某个线程的调度优先级高于其余线程,从而致使饥饿。code
一般,咱们尽可能不要改变线程的优先级。只要改变了线程的优先级,程序的行为就将与平台相关,而且会致使发生饥饿问题的风险。 Thread.yield以及Thread.sleep的语义都是UB,JVM既能够将他们实现为空操做,也能够将它们视为线程调度的参考。
活锁是另外一种形式的活跃性问题,该问题不会致使线程阻塞,但也不能继续执行。由于线程将不断重复执行相同的操做,并且总会失败。 活锁一般发生在处理事务消息的应用程序中:若是不能成功处理某个消息,那么消息处理机制将回滚整个事务,并将它从新放到队列的开头。当多个相互协做的线程都对彼此进行响应从而修改各自的状态,并使得任何一个线程没法继续执行时,就发生了活锁,在并发应用程序中,经过等待随机长度的时间和回退能够有效避免活锁的发生。对象