活锁通常指的是线程总是在持续重复执行一个失败的操作,以至于线程无法继续执行的情况。饿死通常指的是线程一直被调度器延迟访问其需要的资源,比如调度器一直执行优先级别高的线程,而总有优先级别高的线程可以执行,所以此线程就会被无限延期,这种无限延期是导致线程"饿死"的直接原因。通常我们可以使用sleep方法来避免线程被饿死,通过调用线程的sleep方法让高优先级线程给低优先级线程执行的机会。
死锁的产生与过多使用同步有直接的关系,也就是说为了避免多线程问题而提出的同步解决方案带来了死锁问题。简单的说就是线程ThreadA持有线程ThreadB的资源锁,恰好此时线程ThreadB也持有ThreadA的资源锁,而释放锁的前提是它们必须获取对方现在持有的锁,这就导致线程都无法继续执行下去,继而产生了死锁问题。为了描述死锁,我们看一个实例:
例子中分别创建了两个方法,在方法testMethodA中的加锁顺序与方法testMethodB中的加锁顺序刚好有交叉,为了演示的效果,使用了sleep方法,在程序运行一段时间后就会因死锁而停止执行。
这个例子的死锁问题是显而易见的,但是更多的情况是不这么明显。可能在多个包中的多个类存在关联调用,而这种情况是很难被发现的。遗憾的是java语言和java虚拟机并没有提供一种避免死锁的方式,避免死锁只能靠程序员自己来解决,比如在一个同步方法中尽量避免去调用另外一个同步方法,虽然在很多情况下不可避免会发生同步方法的嵌套调用,但是这依然是最简单有效的避免死锁的方式。