Java 并发编程(四):如何保证对象的线程安全性
发布日期:2021-04-30 21:10:00 浏览次数:104 分类:精选文章

本文共 2205 字,大约阅读时间需要 7 分钟。

Java 并发编程实战:对象线程安全性的探讨

01、前言

《Java 并发编程实战》这本书虽然被奉为并发编程的经典之作,但它的第四章“对象的组合”实在太过枯燥。第四章“对象的组合”之所以令人痛苦,可能是因为它涉及到线程安全性的设计和实现,这是一个需要深入思考的话题。

在学习过程中,我深深感受到技术书籍的枯燥,但为了进步,只能硬着头皮读下去。希望通过这篇文章,能够对线程安全性的理解更加深入。

02、线程安全类的设计

线程安全类的设计需要遵循三个关键步骤:

  • 找出表示对象状态的所有变量

    对于一个普通的计数器类 Counter,其状态变量只有一个——value。这个变量表示计数器的当前值。

  • 对变量进行有效性约束

    值的有效性需要通过边界条件来约束。例如,在 Counter 类中,value 的取值范围应该在 0Integer.MAX_VALUE 之间。同时,我们还需要对异常情况进行处理,例如当 value 达到最大值时,需要抛出异常。

  • 增加类的并发访问策略

    直接在方法上加上 synchronized 关键字,就可以确保线程安全。例如:

    public synchronized int getValue() {
    return value;
    }
    public synchronized int increment() {
    if (value == Integer.MAX_VALUE) {
    throw new IllegalStateException("counter overflow");
    }
    return ++value;
    }
  • 通过以上三个步骤,我们就可以设计出一个线程安全的 Counter 类。

    03、非线程安全对象的处理

    在上述讨论中,我们谈到了线程安全类的设计。那么问题来了:如果一个类本身不是线程安全的,如何保证它作为对象使用时的线程安全性?

    作者提出了“封闭机制”的概念:

  • 将对象作为类的私有成员变量;
  • 将对象作为方法内部的局部变量;
  • 线程 A 不将对象传递给线程 B,而是通过其他方式共享。
  • 例如,StringList 类中的 myList 是私有的,而 addStringremoveString 方法都加上了 synchronized 关键字。通过这种方式,我们可以确保 myList 的线程安全性。

    需要注意的是,ArrayList 本身并不是线程安全的,但通过将其封装在一个线程安全的类中,我们可以实现线程安全。

    04、在已有的线程安全类上追加功能

    假设我们已经有一个线程安全类 StringList,它包含了大部分我们需要的功能。现在,我们需要在这个类上追加新的功能,例如添加一个 addIfNotExist 方法:

    public class StringList {
    private List
    myList = new ArrayList<>();
    public synchronized void addString(String s) {
    myList.add(s);
    }
    public synchronized void addIfNotExist(String s) {
    boolean isExist = myList.contains(s);
    if (!isExist) {
    myList.add(s);
    }
    }
    }

    新增的 addIfNotExist 方法没有破坏原有的线程安全性,因为它仍然是线程安全的。然而,在一些情况下,我们可能无法直接修改源码。这个时候,可以通过继承的方式来实现功能扩展:

    public class StringList {
    protected List
    myList = new ArrayList<>();
    public synchronized void addString(String s) {
    myList.add(s);
    }
    }
    public class NewStringList extends StringList {
    public synchronized void addIfNotExist(String s) {
    boolean isExist = myList.contains(s);
    if (!isExist) {
    myList.add(s);
    }
    }
    }

    这种方式的前提是父类中的 myListprotected 而不是 private 的。

    05、总结

    从上述讨论中可以看出,线程安全性的设计需要从三个方面入手:状态变量的有效性、并发访问策略的设计,以及封闭机制的应用。通过合理的设计和优化,我们可以在现有的线程安全类上追加功能,确保整个系统的线程安全性。

    虽然《Java 并发编程实战》这本书的第四章“对象的组合”确实非常枯燥,但通过深入理解线程安全性的设计原理,我们可以逐步破解它的奥秘。希望未来能有更多有趣的内容等待我们去探索。

    上一篇:综合实验:狐狸逮兔子
    下一篇:计算机专业毕业做软件测试丢人吗?

    发表评论

    最新留言

    留言是一种美德,欢迎回访!
    [***.207.175.100]2026年06月04日 03时32分35秒

    关于作者

        喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
    -- 愿君每日到此一游!

    推荐文章