本文共 2205 字,大约阅读时间需要 7 分钟。
Java 并发编程实战:对象线程安全性的探讨
01、前言
《Java 并发编程实战》这本书虽然被奉为并发编程的经典之作,但它的第四章“对象的组合”实在太过枯燥。第四章“对象的组合”之所以令人痛苦,可能是因为它涉及到线程安全性的设计和实现,这是一个需要深入思考的话题。
在学习过程中,我深深感受到技术书籍的枯燥,但为了进步,只能硬着头皮读下去。希望通过这篇文章,能够对线程安全性的理解更加深入。
02、线程安全类的设计
线程安全类的设计需要遵循三个关键步骤:
找出表示对象状态的所有变量
对于一个普通的计数器类Counter,其状态变量只有一个——value。这个变量表示计数器的当前值。 对变量进行有效性约束
值的有效性需要通过边界条件来约束。例如,在Counter 类中,value 的取值范围应该在 0 到 Integer.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、非线程安全对象的处理
在上述讨论中,我们谈到了线程安全类的设计。那么问题来了:如果一个类本身不是线程安全的,如何保证它作为对象使用时的线程安全性?
作者提出了“封闭机制”的概念:
例如,StringList 类中的 myList 是私有的,而 addString 和 removeString 方法都加上了 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); } }} 这种方式的前提是父类中的 myList 是 protected 而不是 private 的。
05、总结
从上述讨论中可以看出,线程安全性的设计需要从三个方面入手:状态变量的有效性、并发访问策略的设计,以及封闭机制的应用。通过合理的设计和优化,我们可以在现有的线程安全类上追加功能,确保整个系统的线程安全性。
虽然《Java 并发编程实战》这本书的第四章“对象的组合”确实非常枯燥,但通过深入理解线程安全性的设计原理,我们可以逐步破解它的奥秘。希望未来能有更多有趣的内容等待我们去探索。
发表评论
最新留言
关于作者