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.

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

相关文章
|
4天前
|
Java 程序员 开发者
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
45 14
|
7天前
|
安全 Java 程序员
Java 面试必问!线程构造方法和静态块的执行线程到底是谁?
大家好,我是小米。今天聊聊Java多线程面试题:线程类的构造方法和静态块是由哪个线程调用的?构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节有助于掌握Java多线程机制。下期再见! 简介: 本文通过一个常见的Java多线程面试题,详细讲解了线程类的构造方法和静态块是由哪个线程调用的。构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节对掌握Java多线程编程至关重要。
38 13
|
8天前
|
安全 Java 开发者
【JAVA】封装多线程原理
Java 中的多线程封装旨在简化使用、提高安全性和增强可维护性。通过抽象和隐藏底层细节,提供简洁接口。常见封装方式包括基于 Runnable 和 Callable 接口的任务封装,以及线程池的封装。Runnable 适用于无返回值任务,Callable 支持有返回值任务。线程池(如 ExecutorService)则用于管理和复用线程,减少性能开销。示例代码展示了如何实现这些封装,使多线程编程更加高效和安全。
|
1月前
|
安全 Java 程序员
面试直击:并发编程三要素+线程安全全攻略!
并发编程三要素为原子性、可见性和有序性,确保多线程操作的一致性和安全性。Java 中通过 `synchronized`、`Lock`、`volatile`、原子类和线程安全集合等机制保障线程安全。掌握这些概念和工具,能有效解决并发问题,编写高效稳定的多线程程序。
68 11
|
1月前
|
缓存 安全 算法
Java 多线程 面试题
Java 多线程 相关基础面试题
|
1月前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
110 17
|
2月前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
7月前
|
存储 SQL 安全
Java共享问题 、synchronized 线程安全分析、Monitor、wait/notify以及锁分类
Java共享问题 、synchronized 线程安全分析、Monitor、wait/notify以及锁分类
65 0
|
9月前
|
存储 安全 Java
深入理解Java并发编程:线程安全与锁机制
【5月更文挑战第31天】在Java并发编程中,线程安全和锁机制是两个核心概念。本文将深入探讨这两个概念,包括它们的定义、实现方式以及在实际开发中的应用。通过对线程安全和锁机制的深入理解,可以帮助我们更好地解决并发编程中的问题,提高程序的性能和稳定性。
|
9月前
|
安全 Java API
Java 8中的Stream API:简介与实用指南深入理解Java并发编程:线程安全与锁优化
【5月更文挑战第29天】本文旨在介绍Java 8中引入的Stream API,这是一种用于处理集合的新方法。我们将探讨Stream API的基本概念,以及如何使用它来简化集合操作,提高代码的可读性和效率。 【5月更文挑战第29天】 在Java并发编程中,线程安全和性能优化是两个核心议题。本文将深入探讨如何通过不同的锁机制和同步策略来保证多线程环境下的数据一致性,同时避免常见的并发问题如死锁和竞态条件。文章还将介绍现代Java虚拟机(JVM)针对锁的优化技术,包括锁粗化、锁消除以及轻量级锁等概念,并指导开发者如何合理选择和使用这些技术以提升应用的性能。

热门文章

最新文章