等待线程由于唤醒其所需的条件永远无法成立.或者其他线程无法唤醒这个线程而一直处于非运行状态(线程并未终止)导致其任务一直无法进展. 那么我们就称这个线程被锁死(Lockout)。
锁死的几种情况
信号丢失锁死
信号丢失锁死是由于没有相应的通知线程来唤醒等待线程而使等待线程一直处于等待状态的一种活性故障。
信号丢失锁死的一个典型例子是等待线程在执行 Object.wait()/Condition.await()前没有对保护条件进行判断,而此时保护条件实际上可能巳然成立,然而此后可能并无其他线 程更新相应保护条件涉及的共享变扭使其成立并通知等待线程,这就使得等待线程一直处于等待状态,从而使其任务一直无法进展。
一个常见例子是CountDownLatch.countDown()调用没有放在finally块中导致CountDownLatch.await()的执行线程一直处于等待状态, 从而使其任务一直无法进展。
嵌套监视器锁死
嵌套监视器锁死(Nested Monitor Lockout)是嵌套锁导致等待线程永远无法被唤醒的活性故障。线程饥饿(Thread Starvation)
是指线程一直无法获得其所需的资源而导致其任务一 直无法进展的一种活性故障。
线程饥饿的一个典型例子是在高争用 的环境下使用非公平模式(Non-fairmode)的读写锁(ReentrantReadWriteLock)。
产生条件是一个(或者多个)线程始终无法获取其所需的资源,显然这个条件的 满足并不意味着死锁产生的必要条件(这还仅是必要条件,而不是充分条件) 的满足,因此线程饥饿并不会导致死锁。线程饥饿涉及的线程,其生命周期状态不一定就是WATING或者BLOCKED状态, 其状态也可能是RUNNING(这说明涉及的线程一直在申请其所需的资源),这时饥饿就演变成7.4节介绍的活锁
活锁
活锁(Livelock)是指线程一直处于运行状态,但是其任务却一直无法进展的一种活性故障。线程一直在申请其所需的资源而一直未申请成功, 那么此时线程饥饿实际上就演变成活锁。
活锁同样会发生在多个相互协作的线程间,当他们为了彼此间的响应而相互礼让,使得没有一个线程能够继续前进,那么就发生了活锁。