Java Concurrencyin Practice 并发编程实践系列 第二章 线程安全 Thread Safety 下

简介: Java Concurrencyin Practice 并发编程实践系列 第二章 线程安全 Thread Safety 下

Chapter 2: Thread Safety

第二章,主要讲的是线程安全的问题,及解决方法,现在写的是如何去理解线程安全,下一篇写2.1 What is thread safety

Whenever more than one thread accesses a given state variable, and one of them might write to it, they all must coordinate their access to it using synchronization.

当多个线程访问同一个状态变量,并且其中一个线程可能对其进行写操作时,它们必须使用同步机制来协调对该变量的访问。

The primary mechanism for synchronization in Java is the synchronized keyword, which provides exclusive locking, but the term “synchronization” also includes the use of volatile variables, explicit locks, and atomic variables.

在Java中,同步的主要机制是使用synchronized关键字,它提供了(提供独占锁定/排他性的锁定)排它锁。但是,“同步”这个术语还包括使用volatile变量显式锁原子变量

  1. volatile变量volatile关键字用于声明变量,确保线程之间对该变量的读写操作具有可见性。它可以防止指令重排序缓存一致性问题,但不提供原子性。
  2. 显式锁:Java中的Lock接口及其实现类(如ReentrantLock)提供了显式的加锁和解锁操作。通过使用显式锁,可以更细粒度地控制线程之间的同步,并提供更灵活的锁定机制。
  3. 原子变量:Java中的java.util.concurrent.atomic包提供了一组原子类,如AtomicIntegerAtomicLong等。这些类提供了原子性的操作,可以确保特定操作在多线程环境下的原子执行。

You should avoid the temptation to think that there are “special” situations in which this rule does not apply. A program that omits needed synchronization might appear to work, passing its tests and performing well for years, but it is still broken and may fail at any moment.

并发编程中,我们应该避免认为存在“特殊”情况不需要遵守同步规则。一个省略了必要同步的程序可能会看起来工作正常,通过测试并在很长时间内表现良好,但它仍然存在缺陷,随时可能发生故障。

即使一个程序在某个特定的环境下运行良好,没有出现问题,也不能保证它在其他环境或将来的时刻依然正常工作。并发程序的行为是不确定的,因为线程的执行顺序和交互是受到多种因素影响的,包括底层硬件和操作系统的调度策略。

因此,必须始终遵循同步规则,并根据需要正确地使用同步机制,以确保共享状态的一致性和可见性。否则,即使看起来正常的程序也可能在某个时刻出现严重的问题。

If multiple threads access the same mutable state variable without appropriate synchronization, your program is broken. There are three ways to fix it:

  • Don’t share the state variable across threads;
  • Make the state variable immutable; or
  • Use synchronization whenever accessing the state variable.

If you haven’t considered concurrent access in your class design, some of these approaches can require significant design modifications, so fixing the problem might not be as trivial as this advice makes it sound.

如果多个线程在没有适当同步的情况下访问同一个可变状态变量,那么你的程序就是有问题的。修复这个问题有三种方式:

  • 不在线程之间共享状态变量;
  • 将状态变量设置为不可变;
  • 在访问状态变量时使用同步机制。

如果你在类的设计中没有考虑并发访问,那么其中一些方法可能需要进行重大的设计修改,因此修复问题可能并不像这些建议听起来那么简单。

It is far easier to design a class to be thread-safe than to retrofit it for thread safety later.

设计一个线程安全的类要比事后为其添加线程安全性更容易。

这句话的意思是,在最初设计类的时候就考虑线程安全性要比在后期对其进行修改和添加线程安全性要容易得多。如果在最初的设计中就充分考虑了并发访问的情况,并采取了适当的同步措施,那么就能够确保类在多线程环境下的安全性。

在事后为类添加线程安全性可能需要对现有的代码进行较大的修改,甚至需要重新设计。这涉及到理解和分析现有代码的并发访问问题,选择适当的同步机制,并确保修改后的代码在各种并发场景下都能正确地工作。因此,为了简化开发过程并减少潜在的错误和问题,最好在最初的设计阶段就考虑并发访问,并设计出线程安全的类。

但在实际情况中,设计一个完全线程安全的类可能并不容易。这可能涉及到复杂的业务逻辑、多个状态变量之间的依赖关系以及高并发场景下的性能考虑等因素。在一些复杂的系统中,确保每个类都是完全线程安全的可能是一项巨大的挑战。

In a large program, identifying whether multiple threads might access a given variable can be complicated.

Fortunately, the same object-oriented techniques that help you write well-organized, maintainable classes—such as encapsulation and data hiding—can also help you create thread-safe classes.

The less code that has access to a particular variable, the easier it is to ensure that all of it uses the proper synchronization, and the easier it is to reason about the conditions under which a given variable might be accessed.

The Java language doesn’t force you to encapsulate state—it is perfectly allowable to store state in public fields (even public static fields) or publish a reference to an otherwise internal object—but the better encapsulated your program state,

the easier it is to make your program thread-safe and to help maintainers keep it that way.

概括一下,上面讲的是通过封装状态并限制对状态的访问,可以更好地控制多线程环境下的数据共享和访问,从而使程序更容易维护和确保线程安全性。

相关文章
|
1天前
|
安全 Java 调度
Java 并发编程中的线程安全和性能优化
本文将深入探讨Java并发编程中的关键概念,包括线程安全、同步机制以及性能优化。我们将从基础入手,逐步解析高级技术,并通过实例展示如何在实际开发中应用这些知识。阅读完本文后,读者将对如何在多线程环境中编写高效且安全的Java代码有一个全面的了解。
|
10天前
|
缓存 监控 Java
Java中的并发编程:理解并应用线程池
在Java的并发编程中,线程池是提高应用程序性能的关键工具。本文将深入探讨如何有效利用线程池来管理资源、提升效率和简化代码结构。我们将从基础概念出发,逐步介绍线程池的配置、使用场景以及最佳实践,帮助开发者更好地掌握并发编程的核心技巧。
|
9天前
|
监控 算法 Java
掌握Java的垃圾回收机制:从原理到实践
在Java的世界中,垃圾回收(Garbage Collection,简称GC)是一块神秘的领域,它如同一位默默无闻的清洁工,确保内存中不再使用的对象得到妥善处理。本文将带你走进垃圾回收的大门,探索它的工作原理、常见算法及其在实际应用中的调优策略。无论你是初学者还是有一定经验的开发者,这篇文章都将为你揭开垃圾回收的神秘面纱,让你的Java程序运行得更加高效和稳定。
24 5
|
11天前
|
安全 Java 测试技术
掌握Java的并发编程:解锁高效代码的秘密
在Java的世界里,并发编程就像是一场精妙的舞蹈,需要精准的步伐和和谐的节奏。本文将带你走进Java并发的世界,从基础概念到高级技巧,一步步揭示如何编写高效、稳定的并发代码。让我们一起探索线程池的奥秘、同步机制的智慧,以及避免常见陷阱的策略。
|
16天前
|
存储 Java 程序员
优化Java多线程应用:是创建Thread对象直接调用start()方法?还是用个变量调用?
这篇文章探讨了Java中两种创建和启动线程的方法,并分析了它们的区别。作者建议直接调用 `Thread` 对象的 `start()` 方法,而非保持强引用,以避免内存泄漏、简化线程生命周期管理,并减少不必要的线程控制。文章详细解释了这种方法在使用 `ThreadLocal` 时的优势,并提供了代码示例。作者洛小豆,文章来源于稀土掘金。
|
16天前
|
数据采集 Java 数据挖掘
Java IO异常处理:在Web爬虫开发中的实践
Java IO异常处理:在Web爬虫开发中的实践
|
16天前
|
Java UED 开发者
Java中的异常处理:理解与实践
【9月更文挑战第3天】在Java编程中,异常处理是保持程序健壮性的关键。本文将引导你了解Java的异常机制,从基本的try-catch结构到自定义异常类的创建,以及如何优雅地处理异常情况。我们将一起探讨异常处理的最佳实践,并学习如何在代码中实现它们,以确保你的应用程序能够优雅地处理运行时错误。
13 2
|
19天前
|
Java 调度
Java中的多线程基础与实践
【8月更文挑战第31天】本文将深入浅出地讲解Java中多线程的基础知识,并通过实例展示如何在Java程序中实现多线程。我们将从多线程的基本概念出发,逐步深入到线程的创建、控制以及同步机制,最后通过一个简易版的生产者消费者模型来实践这些知识点。文章旨在帮助初学者快速掌握多线程编程的关键技能,并理解其背后的原理。
|
10天前
|
Java 数据库连接 开发者
Java中的异常处理:理解与实践
【9月更文挑战第9天】在Java编程的海洋里,异常处理是一艘不可或缺的救生艇。它不仅保护你的代码免受意外错误的侵袭,还能确保你的应用在遇到困难时能优雅地继续航行。本文将带你深入了解Java的异常处理机制,通过浅显易懂的方式,让你掌握如何捕捉和处理异常,以及如何自定义异常类型来应对特定的业务需求。无论你是Java新手还是资深开发者,这篇文章都将为你提供宝贵的知识和技巧,让你的代码更加健壮和可靠。
|
19天前
|
C# 开发者 数据处理
WPF开发者必备秘籍:深度解析数据网格最佳实践,轻松玩转数据展示与编辑大揭秘!
【8月更文挑战第31天】数据网格控件是WPF应用程序中展示和编辑数据的关键组件,提供排序、筛选等功能,显著提升用户体验。本文探讨WPF中数据网格的最佳实践,通过DevExpress DataGrid示例介绍其集成方法,包括添加引用、定义数据模型及XAML配置。通过遵循数据绑定、性能优化、自定义列等最佳实践,可大幅提升数据处理效率和用户体验。
40 0