Java并发编程(四)活跃度

    xiaoxiao2025-07-22  8

    4. 活跃度

    一个并发应用及时执行的能力称作活跃度。本节介绍最常见的活跃度问题,死锁,然后继续简单介绍两种其他的活跃度问题,饥饿和活锁。

    4.1 死锁

    死锁介绍了两个或者多个线程永远阻塞、彼此等待的情形。这是一个例子, 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时,极有可能阻塞。两个阻塞都不会结束,因为两个线程都在等待另一个线程结束鞠躬。

    4.2 饥饿和活锁

    饥饿和活锁问题没有死锁那么常见,但是仍然是一个并发程序开发者需要考虑的问题。

    4.2.1 饥饿

    饥饿指的是线程无法访问共享数据,并且无法继续执行。当共享数据被线程长时间占有的时候,该现象就会发生。例如,假设一个对象提供了一个耗时比较长的同步化方法。如果一个线程频繁地调用该方法,其他需要频繁调用该方法的线程就会经常被阻塞。

    4.2.2 活锁

    一个线程经常对另一个线程作出回应。如果另一个线程对其他线程又要作出回应,那么活锁就可能发生。和死锁一样,活锁也会导致程序无法继续运行。然而,线程并没有被阻塞——它们仅仅忙于回应其他线程无法继续执行任务。这类似于两个人在一个走廊中过路:Alphonse移到左边让Gaston通过,Gaston移到右边让Alphonse通过。由于他们被彼此阻塞,Alphonse移到右边,Gaston移到左边。他们又会发生阻塞,一直循环下去。。。

    文章翻译自Java Tutorials, Concurrency,翻译难免会有纰漏,欢迎读者讨论指正。

    转载请注明原文地址: https://ju.6miu.com/read-1300932.html
    最新回复(0)