并发——死锁活锁(Java se tutorial翻译)

4.活度(Liveness)

一个并发程序能够及时执行的能力称之为活度(Liveness)。本节介绍死锁、饿死和活锁

 

4.1 死锁(Deadlock)

死锁描述了两个或多个线程因相互等待而永远阻塞的问题。下面举例说明。

 

Alphonse 和 Gaston 是好朋友,都是礼仪的信仰者。礼仪中一个严格的规则是,当你向你的朋友鞠躬时,你必须保持鞠躬状态,直到你的朋友有机会鞠躬回礼。不幸的是,这个规则没有考虑两个朋友同时相互鞠躬的情形。下面Deadlock的例子,模拟了这种情况:

 

public class Deadlock {
    static class Friend {
        private final String name;
        public Friend(String name) {
            this.name = name;
        }
        public String getName() {
            return this.name;
        }
        public synchronized void bow(Friend bower) {
            System.out.format("%s: %s"
                + "  has bowed to me!%n", 
                this.name, bower.getName());
            bower.bowBack(this);
        }
        public synchronized void bowBack(Friend bower) {
            System.out.format("%s: %s"
                + " has bowed back to me!%n",
                this.name, bower.getName());
        }
    }
 
    public static void main(String[] args) {
        final Friend alphonse =
            new Friend("Alphonse");
        final Friend gaston =
            new Friend("Gaston");
        new Thread(new Runnable() {
            public void run() { alphonse.bow(gaston); }
        }).start();
        new Thread(new Runnable() {
            public void run() { gaston.bow(alphonse); }
        }).start();
    }
}

 

当运行Deadlock时,当调用bowBack时,很可能两个线程都会阻塞。没有阻塞能够结束,因为每个线程都在等待另一个结束bow。

 

4.2 饿死和活锁

饿死和活锁问题比死锁要碰到的少一些。但是并发程序设计者仍然会碰到的问题。

 

饿死

饿死是指一个线程不能够获得共享资源,因而不能够继续执行。这种情况的发生,是因为有贪婪的线程长时间占着共享资源。例如,一个对象上的同步方法要很长时间才能返回。如果一个线程频繁调用这个方法,其它需要经常访问该方法的线程就会进程被阻塞。

活锁

一个线程经常需要根据另一个线程的动作而采取相应的动作。如果另一个线程也需要根据这个线程而动作,就可能导致活锁。和死锁一样,活锁的线程也无法继续执行。但是线程并没有被阻塞——它们只是相互间忙于响应对方而无法继续进行。这就像两个人在走廊上相向相遇一样:Alphonse向左移想让Gaston通过,而Gaston也同时向右移想让Alpnonse通过。这样反复多次,他们仍然无法通过。

    原文作者:java锁
    原文地址: https://blog.csdn.net/dusin/article/details/8492630
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞