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内存模型(JMM)的复杂性及其对并发编程的影响,不同于传统的摘要形式,本文将以一个实际案例为引子,逐步揭示JMM的核心概念,包括原子性、可见性、有序性,以及这些特性在多线程环境下的具体表现。通过对比分析不同并发工具类的应用,如synchronized、volatile关键字、Lock接口及其实现等,本文将展示如何在实践中有效利用JMM来设计高效且安全的并发程序。最后,还将简要介绍Java 8及更高版本中引入的新特性,如StampedLock,以及它们如何进一步优化多线程编程模型。 ####
31 0
|
11天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
13天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
13天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。
|
13天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
35 3
|
13天前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
93 2
|
21天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
46 6
|
1月前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
|
30天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
30天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
50 3