`

《Java并发编程》之七:避免活跃性危险

    博客分类:
  • Java
阅读更多

如果所有线程以固定顺序来获取锁,那么在程序中就不会出现锁顺序死锁问题。

通过锁顺序来避免死锁:

public class InduceLockOrder {
    private static final Object tieLock = new Object();

    public void transferMoney(final Account fromAcct,
                              final Account toAcct,
                              final DollarAmount amount)
            throws InsufficientFundsException {
        class Helper {
            public void transfer() throws InsufficientFundsException {
                if (fromAcct.getBalance().compareTo(amount) < 0)
                    throw new InsufficientFundsException();
                else {
                    fromAcct.debit(amount);
                    toAcct.credit(amount);
                }
            }
        }
        int fromHash = System.identityHashCode(fromAcct);
        int toHash = System.identityHashCode(toAcct);

        if (fromHash < toHash) {
            synchronized (fromAcct) {
                synchronized (toAcct) {
                    new Helper().transfer();
                }
            }
        } else if (fromHash > toHash) {
            synchronized (toAcct) {
                synchronized (fromAcct) {
                    new Helper().transfer();
                }
            }
        } else {
            synchronized (tieLock) {
                synchronized (fromAcct) {
                    synchronized (toAcct) {
                        new Helper().transfer();
                    }
                }
            }
        }
    }

    interface DollarAmount extends Comparable<DollarAmount> {
    }

    interface Account {
        void debit(DollarAmount d);

        void credit(DollarAmount d);

        DollarAmount getBalance();

        int getAcctNo();
    }

    class InsufficientFundsException extends Exception {
    }
}

 

10.1.3  在协作对象之间发生的死锁

如果在持有锁时调用某个外部方法,那么将出现活跃性问题。在这个外部方法中可能会获取其他锁,或者阻塞时间过长,导致其他线程无法及时获得当前被持有的锁。

如果在调用某个方法的时候不需要持有锁,那么这种调用被称为开放调用Open Call ,依赖于开放调用的类通常能表现出更好的行为,也更易于编写。

class CooperatingNoDeadlock {
    @ThreadSafe
    class Taxi {
        @GuardedBy("this")
        private Point location, destination;
        private final Dispatcher dispatcher;

        public Taxi(Dispatcher dispatcher) {
            this.dispatcher = dispatcher;
        }

        public synchronized Point getLocation() {
            return location;
        }

        public synchronized void setLocation(Point location) {
            boolean reachedDestination;
            synchronized (this) {
                this.location = location;
                reachedDestination = location.equals(destination);
            }
            if (reachedDestination)
                dispatcher.notifyAvailable(this);
        }

        public synchronized Point getDestination() {
            return destination;
        }

        public synchronized void setDestination(Point destination) {
            this.destination = destination;
        }
    }

    @ThreadSafe
    class Dispatcher {
        @GuardedBy("this")
        private final Set<Taxi> taxis;
        @GuardedBy("this")
        private final Set<Taxi> availableTaxis;

        public Dispatcher() {
            taxis = new HashSet<Taxi>();
            availableTaxis = new HashSet<Taxi>();
        }

        public synchronized void notifyAvailable(Taxi taxi) {
            availableTaxis.add(taxi);
        }

        public Image getImage() {
            Set<Taxi> copy;
            synchronized (this) {
                copy = new HashSet<Taxi>(taxis);
            }
            Image image = new Image();
            for (Taxi t : copy)
                image.drawMarker(t.getLocation());
            return image;
        }
    }

    class Image {
        public void drawMarker(Point p) {
        }
    }

}

 在程序中尽量使用开放调用。与那些在持有锁的时候调用外部方法程序相比,更易于对依赖于开放调用的程序进行死锁分析。

 

10.2  死锁的避免与诊断

尽可能使用开放调用,这能极大简化死锁分析过程。

支持定时的锁:显示使用Lock类中的定时tryLock功能来代替内置锁机制。这项技术只有在同时获取两个锁时才有效,如果在嵌套方法调用中请求多个锁,还是不行。

 

10.3  其他活跃性问题

饥饿:

当线程由于无法访问它所需要的资源而不能继续执行时,就发生饥饿starvation。最常见的资源就是CUP时钟周期,比如对线程的优先级使用不当就会出现这种情况。

要避免使用java的线程优先级,因为这会增加平台依赖性,并可能导致活跃性问题。

 

糟糕的响应性:

如果一个线程长时间占有一个锁,而其他想要访问这个容器的线程就必须等待很长时间。

 

活锁:

Livelock经常发生在处理事务消息的应用程序中,如果不能成功处理某个消息,那么消息处理机制将回滚整个事务,并将它重新放到队列开头,然后循环往复的执行,又把它放到开头。

通过在重试机制中引入随机性。可以有效的避免活锁的发生。

 

小结:活跃性故障时一个非常严重的问题,因为当出现活跃性故障时,除了终止应用程序之外没有其他任何机制可以帮助从这种故障恢复过来。最常见的活跃性故障就是锁顺序死锁。在设计的时候应该避免产生锁顺序死锁,确保线程在获取多个锁时采用一致顺序,同时防止嵌套调用锁,最好使用开放调用。

 

本人博客已搬家,新地址为:http://yidao620c.github.io/

分享到:
评论

相关推荐

    Java并发编程实战华章专业开发者书库 (Tim Peierls 等 美Brian Goetz).pdf

    第三部分聚焦于性能优化,讲解了如何避免活跃性问题(如死锁和活锁)以及如何提高并发代码的性能和可伸缩性。此外,还介绍了测试并发代码正确性和性能的实用技巧,这对于在生产环境中确保程序的稳定性和效率至关重要...

    Java并发编程实战

    第10章 避免活跃性危险 第11章 性能与可伸缩性 第12章 并发程序的测试 第四部分 高级主题 第13章 显式锁 第14章 构建自定义的同步工具 第15章 原子变量与非阻塞同步机制 第16章 Java内存模型 附录A 并发性...

    Java并发编程设计原则和模式

    本资料“Java并发编程设计原则和模式”深入探讨了如何在Java环境中有效地进行并发处理,以充分利用系统资源并避免潜在的并发问题。 一、并发编程基础 并发是指两个或多个操作在同一时间段内执行,但并不意味着这些...

    java并发编程经典书籍(英文版)

    Java并发编程是Java开发者必须掌握的关键技能之一,尤其是在多核处理器和分布式系统广泛使用的今天。以下是对标题和描述中提及的两本经典书籍——《Concurrent Programming in Java》和《Java Concurrency in ...

    Java 并发编程实战

    第10章 避免活跃性危险 第11章 性能与可伸缩性 第12章 并发程序的测试 第四部分 高级主题 第13章 显式锁 第14章 构建自定义的同步工具 第15章 原子变量与非阻塞同步机制 第16章 Java内存模型 附录A 并发性...

    Java并发编程实战2019.zip

    Java并发编程实战,第1章 简介,第...第10章 避免活跃性危险 第11章 性能与可伸缩性 第12章 并发程序的测试 第13章 显式锁 第14章 构建自定义的同步工具 第15章 原子变量与非阻塞同步机制 第16章 Java内存模型

    Java并发编程实践 PDF 高清版

    本书的读者是那些具有一定Java编程经验的程序员、希望了解Java SE 5,6在线程技术上的改进和新特性的程序员,以及Java和并发编程的爱好者。 目录 代码清单 序 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的...

    java并发编程技术

    Java并发编程技术是Java开发中的重要领域,它涉及到如何在多线程环境下高效地执行程序。并发编程可以充分利用多核处理器资源,提高系统的响应速度和处理能力。以下是一些核心的知识点: 1. **并行程序**:并行程序...

    java并发编程 英文版

    《Java并发编程英文版》是Doug Lea所著的一部关于Java并发编程的经典作品。Doug Lea是计算机科学领域的知名学者,尤其在并发编程、设计模式、软件工程等领域有深入的研究和独到的见解。本书在1996年首次出版,至今仍...

    Java并发编程实战-读书笔记

    《Java并发编程实战》个人读书笔记,非常详细: 1 简介 ...10 避免活跃性危险 11 性能与可伸缩性 12 并发程序的测试 13 显示锁 14 构建自定义的同步工具 15 原子变量与非阻塞同步机制 16 Java内存模型

    Java并发编程实践

    《Java并发编程实践》是一本深入探讨Java平台并发编程的权威著作,由Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowles和David Holmes等专家共同编写。这本书全面介绍了如何在Java环境中有效地设计和实现并发...

    Java Concurrency in Practice Java并发编程

    《Java Concurrency in Practice》是Java并发编程领域的一本权威著作,由Brian Goetz、Tim Peierls、Joshua Bloch、David Holmes和Doug Lea等多位Java并发领域的专家共同编写。这本书深入探讨了Java平台上的多线程和...

    Java并发编程(学习笔记).xmind

    Java并发编程 背景介绍 并发历史 必要性 进程 资源分配的最小单位 线程 CPU调度的最小单位 线程的优势 (1)如果设计正确,多线程程序可以通过提高处理器资源的利用率来提升系统吞吐率 ...

    Java并发编程实战1

    避免活跃性危险章节讨论了可能导致程序停止前进的状况,如死锁、饥饿和活锁。性能与可分析性章节则讲解如何测量和优化并发程序的性能。并发程序的测试是确保代码正确性的关键,这一部分提供了相关的测试策略。 第四...

    《java并发编程实战》读书笔记-第2章-线程安全性

    《java并发编程实战》读书笔记-第2章-线程安全性,脑图形式,使用xmind8制作 包括引言、线程安全性定义、原子性、加锁机制、使用锁保护状态、活跃性与性能等内容

    JAVA并发编程实践_中文版(1-16章全)_1/4

    第10章 避免活跃度危险 第11章 性能和可伸缩性 第12章 测试并发程序 第4部分 高级主题 第13章 显示锁 第14章 构建自定义的同步工具 第15章 原子变量与非阻塞同步机制 第16章 java存储模型 附录a 同步annotation 参考...

    Java并发编程原理与实战1

    Java并发编程是Java开发中不可或缺的一部分,它涉及到多线程、多进程以及系统资源的高效利用。本篇文章将深入探讨并发编程的基本概念、学习路径、重要性和挑战,以及线程的状态转换。 首先,我们需要理解并发与并行...

    Java并发编程part2

    中文完整版的Java并发编程实践PDF电子书 作者:Brian Gogetz Tim Peierls Joshua Bloch Joseph Bowbeer David Holmes Doug Lea 译者:韩锴 方秒 目录 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的优点 1.3 ...

Global site tag (gtag.js) - Google Analytics