了解关键的多线程概念对于软件开发人员至关重要,因为它不仅可以增强技能,还可以直接影响应用程序开发、可扩展性和软件解决方案的整体质量。
在多线程上下文中,原子操作确保一个线程可以执行一系列操作,而不会被其他线程中断。多个线程可能会尝试同时读取或写入共享数据。如果没有原子性,并发修改可能会导致不一致或意外的结果,通常称为竞争条件。
Java 规范保证“读”和“写”是原子操作而不是它们的组合。因此,根据规范,“读取、加 1,然后将结果写回”的操作不是原子操作。此类操作称为复合操作,在我们的代码中使用它们时,它们通常需要是原子的。
原子操作示例:
递增计数器:如果两个线程在没有原子性的情况下同时递增计数器,则它们可能都读取相同的值并写回相同的递增值,从而导致丢失一个增量。
更新共享变量:如果一个线程正在读取一个值,而另一个线程正在修改它,如果没有原子性,读取线程可能会得到不一致的值。
实现原子性:
原子类:许多编程语言提供原子类(例如 Java 中的 AtomicInteger),封装保证原子性的操作。
同步方法/块:在Java等语言中,可以使用synchronized关键字来确保一次只有一个线程可以执行一段代码或一个方法。
锁:使用显式锁(例如 Java 中的 ReentrantLock)来管理对共享资源的访问。
好处
不可变性是指对象在创建后其状态无法修改的属性。在编程中,不可变对象是那些一旦初始化就不能更改或改变的对象。不是修改不可变的对象,而是创建一个具有所需更改的新对象。
不可变意味着一旦对象的构造函数完成执行,该实例就无法更改。
不可变对象的特性
无状态变化: 一旦创建了不可变对象,其状态(属性或字段)在其整个生命周期中保持不变。
线程安全: 不可变对象可以在多个线程之间安全共享,无需同步,因为它们无法修改。
哈希码稳定性: 不可变对象的哈希码在其整个生命周期中保持不变,使其适合在 HashMap 或 HashSet 等基于哈希的集合中使用。
实现不变性:
public record ImmutablePoint(int x, int y) {}
Java: Collections.unmodifyingList(), List.of(), Set.of()
C#: System.Collections.Immutable 中的 ImmutableList、ImmutableArray
Python: 元组本质上是不可变的。
使用 Final 字段: 将类的字段声明为 Final。这确保了在对象构造期间只能分配字段一次。
无 Setter: 避免为可变字段提供 setter 方法。这可以防止外部代码在构造对象后更改对象的状态。
public final class ImmutablePoint { private final int x; private final int y; public ImmutablePoint(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } }
静态工厂方法:不提供公共构造函数,而是使用返回对象新实例的静态工厂方法,明确状态无法更改
构建器模式(对于复杂对象): 对于需要很多参数的对象,使用构建器模式创建不可变对象。构建器累积参数并在最后构造一个不可变的实例。
好处
并发: 如果不可变对象的内部结构有效,则它始终有效。不同的线程不可能在该对象内创建无效状态。因此,不可变对象是线程安全的。
垃圾收集:垃圾收集器更容易对不可变对象做出逻辑决策。
用这些知识武装自己不仅可以增强您编写高性能代码的能力,还可以让您为应对现代软件开发的挑战做好准备,在现代软件开发中,响应能力和可扩展性至关重要。当您继续进入多线程世界时,请记住,您掌握的每个概念都将有助于您作为开发人员的成长以及您创建满足并超越用户期望的应用程序的能力。
请继续关注,我们将在接下来的文章中重点讨论饥饿、死锁、竞争条件、操作系统调度等问题,这将提高您的编程技能并促进您的职业生涯!
非常感谢在线文档、社区和所有可用资源,使本文成为可能。
免责声明:本文由人工智能辅助。文章结构和想法列表是 100% 手动策划和研究的。我校对了所有人工智能生成的文本,以确保信息准确性并添加一些上下文
免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。
Copyright© 2022 湘ICP备2022001581号-3