Java Concurrencyin Practice 并发编程实践系列1

简介: Java Concurrencyin Practice 并发编程实践系列1

Java Concurrencyin Practice 并发编程实践

《Java Concurrency in Practice》是于2006年出版,由Brian Goetz等人合著的一本经典的Java并发编程指南。该书详细介绍了Java平台上的并发编程概念、技术和最佳实践。它提供了丰富的实例和案例研究,帮助开发人员理解和解决并发编程中的常见问题。至今仍然被广泛认可为Java并发编程领域的经典参考书籍之一。

让我们看看17年前的前辈们对并发的理解与实践。

preface

在preface这里大概描述了这本书的由来,因许多工程师随着并发量的提高,从而不断涌现出bug,在2004年java发布java.util.concurrent包,并在2006年针对并发问题,著作了这本书。

At this writing, multicore processors are just now becoming inexpensive enough for midrange desktop systems. Not coincidentally, many development teams are noticing more and more threading-related bug reports in their projects. In a recent post on the NetBeans developer site, one of the core maintainers observed that a single class had been patched over 14 times to fix threading-related problems. Dion Almaer, former editor of TheServerSide, recently blogged (after a painful debugging session that ultimately revealed a threading bug) that most Java programs are so rife with concurrency bugs that they work only “by accident”.

越来越多的开发团队在项目中遇到与线程相关的错误报告。

这导致开发、测试和调试多线程程序变得异常困难,因为并发错误往往无法可预测地显现,而且往往在最糟糕的时候出现,比如在生产环境下、在负载较重时。

大多数 Java 程序都充斥着并发 bug,它们仅仅是“碰巧”可以工作。

Indeed, developing, testing and debugging multithreaded programs can be extremely difficult because concurrency bugs do not manifest themselves predictably. And when they do surface, it is often at the worst possible time—in production, under heavy load.

由于并发性的 bug 不会以可预见的方式自己“蹦”出来,因此多线程程序的开发、测试和调试都会变得极端困难。bug 浮出水面的时刻,通常可能是最坏的时候一一对应于生产环境,就是指在高负载的时候。

One of the challenges of developing concurrent programs in Java is the mismatch between the concurrency features offered by the platform and how developers need to think about concurrency in their programs. The language provides low-level mechanisms such as synchronization and condition waits, but these mechanisms must be used consistently to implement application-level protocols or policies. Without such policies, it is all too easy to create programs that compile and appear to work but are nevertheless broken. Many otherwise excellent books on concurrency fall short of their goal by focusing excessively on low-level mechanisms and APIs rather than design-level policies and patterns.

使用Java 开发并发程序所要面对的挑战之一,是要面对平台提供的各种并发特性之间的不匹配,还有就是程序员在他们的程序中应该如何思考并发性。语言提供了一些低层机制,比如同步和条件等待,但是这些机制在实现应用级的协议与策略时才是必须的。不顾这些策略的约束,很容易创建出一个程序,它在编译和运行时看上去一切正常,不过这其中却存在隐患。很多并发方面相当不错的书都没能达到预期的目标,它们过分地关注于低层的机制和API,而不是设计层面的策略和模式。

Java 5.0 is a huge step forward for the development of concurrent applications in Java, providing new higher-level components and additional low-level mechanisms that make it easier for novices and experts alike to build concurrent applications. The authors are the primary members of the JCP Expert Group that created these facilities; in addition to describing their behavior and features, we present the underlying design patterns and anticipated usage scenarios that motivated their inclusion in the platform libraries.

Our goal is to give readers a set of design rules and mental models that make it easier—and more fun—to build correct, performant concurrent classes and applications in Java.

We hope you enjoy Java Concurrency in Practice.

Brian Goetz

Williston, VT

March 2006

Java 5.0 是在使用Java 开发并发应用程序的进程中,迈出的巨大一步。它提供了新的高层组件以及更多的低层机制,这些将使得一名新手更容易像专家那样去构建并发应用程序。本书的作者都是JCP 专家组的主要成员,正是这个专家组创建了这些新工具:除了去描述新工具的行为和特性,我们还向您展示了它们低层的设计模式,预期的使用场景以及将它们纳入平台核心库的动机。

我们的目标是给读者一些设计法则和理念模型,让读者在使用 Java 构建正确、高效的并发类和应用程序时,变得更容易、更有趣。

Java 5.0 java.util.concurrent

在网上说java.util.concurrent的很多,在什么时候引入就很少介绍, 后面我自己在外网搜了下。

Java的并发工具包(java.util.concurrent)是在Java 5版本中引入的。

Java 5发布于2004年,它引入了许多新的语言特性和库,其中包括了用于并发编程的java.util.concurrent包。

java.util.concurrent包提供了一组并发编程工具和类,用于简化多线程编程和管理并发任务。它包含了诸如线程池(ThreadPoolExecutor)、并发集合(ConcurrentHashMap、ConcurrentLinkedQueue等)、原子变量(AtomicInteger、AtomicLong等)、倒计时门闩(CountDownLatch)等常用的并发构件。这些工具和类的引入使得开发人员能够更方便地编写高效且线程安全的并发代码。

Java的并发工具包的引入极大地改善了并发编程的可用性和可靠性,提供了更高级别的抽象和更强大的工具,使开发人员能够更好地处理并发编程的挑战。这也为后续的Java版本奠定了并发编程的基础,并成为开发高性能和可伸缩性应用程序的重要工具之一。

在java5 之后一些并发编程方面的重要更新

  • Java 6:在Java 6中,对并发工具包进行了一些改进和优化。添加了诸如ConcurrentSkipListMap、ConcurrentSkipListSet和TransferQueue等新的并发集合类。此外,还引入了可重入锁(ReentrantLock)的公平性设置以及Condition条件变量的支持。
  • Java 7:Java 7引入了一些新的并发特性,例如Fork/Join框架,用于高效处理分而治之的并行任务。此外,还添加了Phaser类,用于线程间的同步协作。
  • Java 8:Java 8引入了函数式编程的特性,并在并发编程方面进行了一些增强。添加了CompletableFuture类,用于更方便地处理异步任务和回调。还引入了新的并行流(Parallel Streams)功能,以便更容易地将顺序操作转换为并行操作。
  • Java 9:Java 9在并发编程方面引入了一些新的改进,包括改进的锁实现、改进的并发集合类和更好的并发编程工具支持。

第一章 Introduction 并发介绍

1.1 A (very) brief history of concurrency

作者回顾了计算机行业的发展历程,从早期的单核处理器到现在的多核处理器,解释了为什么并发编程成为当代软件开发的重要议题。

作者提到早期的计算机系统中通常只有一个处理器,因此并发编程并不是一个主要的关注点。然而,随着处理器技术的发展和硬件成本的下降,多核处理器变得越来越普及,使得并发编程成为必要的技能。

作者还提到,并发编程的出现是为了充分利用多核处理器的性能,并发编程的目标是使程序能够同时执行多个任务,并充分利用系统资源。

1.2 Benefits of threads

本节着重强调了使用线程进行并发编程的益处,并介绍了几个与线程相关的优势。

首先,使用线程可以提高程序的响应性。通过将任务分配给不同的线程并同时执行,程序可以更快地响应用户的请求,提供更好的用户体验。

其次,线程可以提高系统的吞吐量。通过并行处理多个任务,系统能够同时执行多个操作,从而提高整体处理能力。

此外,线程还可以更好地利用多核处理器的资源。在多核系统中,使用线程可以充分利用每个核心的处理能力,提高系统的性能。

本节还提到了一些其他的线程优势,例如更好的资源利用、更容易的任务管理和更高的可扩展性。

1.2.3 Simplified handling of asynchronous events

在这节中,提到了synchronous I/O, nonblocking I/O 和 multiplexed I/O(多路复用)。

In a single-threaded application, this means that not only does processing the corresponding request stall, but processing of all requests stalls while the single thread is blocked. To avoid this problem, singlethreaded server applications are forced to use nonblocking I/O, which is far more complicated and error-prone than synchronous I/O.

作者提到在单线程应用中,意味着不仅处理对应请求停止了,处理所有的请求都停止了,当单线程被锁住的时候。而避免这个问题,单线程应用 被迫使用的 非锁住的IO流,这个更复杂和更容易出错 对比同步IO流。

However, if each request has its own thread, then blocking does not affect the processing of other requests.

这里最后提到的每个请求拥有自己的线程的模型是一种常见的处理方式,被称为(one-thread-per-request)模型。在这种模型中,每个请求都会被分配一个独立的线程进行处理,不同请求之间的处理互不影响。如果一个请求发生阻塞,只会影响到该请求对应的线程,而不会影响其他请求的处理。

然而,随着应用程序规模的增大和并发需求的增加,使用"one-thread-per-request"的模型可能会导致线程数量过多,占用大量系统资源,同时线程切换的开销也会增加。这种模型在高并发情况下可能面临线程资源耗尽、上下文切换开销过大等问题。

现代的并发编程模型和框架通常采用了更高效的方式来处理请求,如使用线程池来重用线程、使用异步非阻塞的I/O模型等。这样可以更好地利用系统资源,减少线程创建和销毁的开销,提高并发处理能力。

因此,现在的实践中,不一定每个请求都有自己的线程。相反,更常见的做法是使用线程池来管理一定数量的线程,通过线程池来处理请求。这样可以更好地控制线程的数量,避免线程过多导致的资源浪费,并且通过异步非阻塞的方式处理I/O操作,提高系统的并发性能。

后面,针对

1.3 Risks of threads

主要写了线程带来的风险和挑战,包括以下几个方面:

  1. Safety hazards: 线程间共享数据可能导致数据竞争和并发访问的安全问题。并发访问共享数据时,如果没有正确地进行同步和互斥操作,可能导致数据不一致或者出现意外的结果。
  2. Liveness hazards: 线程间的相互依赖和资源竞争可能导致死锁、活锁和饥饿等问题。死锁指的是多个线程因相互等待对方释放资源而无法继续执行;活锁指的是线程在不断重试导致无法取得进展;饥饿指的是某个线程因无法获取所需的资源而一直无法执行。
  3. Performance hazards: 线程的创建和上下文切换会带来一定的开销,如果过度使用线程可能导致系统性能下降。同时,线程间的竞争和同步操作也可能引入额外的开销。
  4. Scalability hazards: 多线程的并发编程需要考虑系统的可扩展性。如果设计不当,过多的线程可能导致系统资源耗尽、上下文切换开销过大等问题,限制了系统的可扩展性和并发性能。
  5. Debugging and testing hazards: 并发程序的调试和测试更加困难,由于并发bug不易预测和重现,需要更加谨慎地进行测试和调试,以确保程序的正确性和稳定性。

这章也会在后面着重讲解,对并发编程来说非常重要。

1.4 Threads are everywhere

这一章节主要强调了线程在现代计算中的普遍存在性和重要性。

  1. 线程的广泛应用:现代计算中的几乎所有领域都使用了线程,包括操作系统、服务器、桌面应用程序、移动应用程序、游戏和嵌入式系统等。线程的使用使得程序能够同时执行多个任务,提高了系统的并发性和性能。
  2. 用户界面响应性:在用户界面的开发中,线程的使用至关重要。通过将用户界面的操作放在单独的线程中,可以确保用户界面的响应性,防止阻塞用户操作的情况发生。
  3. 并发编程挑战:尽管线程在提高系统性能和响应性方面有很大的优势,但并发编程也带来了一些挑战。线程之间的同步、竞争条件、死锁和活锁等问题都可能导致程序的错误行为和性能问题。
  4. 基于任务的编程模型:现代并发编程趋向于使用基于任务的编程模型,即将程序划分为多个独立的任务,并通过线程池等机制来执行这些任务。这种模型简化了并发编程,并提供了更好的可伸缩性和性能。
  5. 并发性的未来:随着计算机系统变得更加复杂和并发,对并发编程的需求也越来越高。并发性将继续是软件开发的重要领域,需要不断发展新的技术和工具来简化并发编程,并提供更好的性能和可靠性。

总的来说,本章强调了线程在现代计算中的普遍应用,并指出了并发编程所面临的挑战和发展趋势。了解并掌握并发编程的原理和技术对于开发高性能和可靠的软件系统至关重要。

总结

该书详细介绍了Java平台上的并发编程概念、技术和最佳实践。它提供了丰富的实例和案例研究,帮助开发人员理解和解决并发编程中的常见问题。

该书的内容主要分为四个部分:

第一部分介绍了并发编程的基础知识和背景

  • 探讨了并发编程的挑战、线程安全性、共享对象、对象的构造和发布、线程封闭性等概念。此部分还介绍了Java中用于构建并发应用程序的基本机制,如线程、锁、条件等。

第二部分深入讨论了共享对象的可变性

  • 涵盖了原子性、可见性和有序性等概念,并介绍了Java中的原子类、volatile关键字和显式锁等工具。此部分还讨论了常见的并发问题,如竞态条件、死锁、饥饿和活跃性问题,并提供了解决这些问题的技巧和模式。

第三部分介绍了并发编程的高级主题

  • 包括线程池、执行器框架、同步容器类、并发工具类、非阻塞算法等内容。此部分还讨论了性能优化、性能测试和调试技术,以及如何设计并发应用程序。

第四部分涵盖了一些特殊的并发主题

  • 如并发集合、原子变量、显式锁、同步器和并发编程的最佳实践等。此外,该书还提供了一些示例代码和实际应用的案例研究,以帮助读者更好地理解并发编程的概念和技术。

《Java Concurrency in Practice》被广泛认为是学习和实践Java并发编程的权威参考。它提供了全面而深入的内容,涵盖了从基础知识到高级技术的方方面面。无论是初学者还是有经验的Java开发人员,都可以从中获得宝贵的知识和实践经验,从而提升自己在并发编程领域的能力。

目录
打赏
0
0
0
0
5
分享
相关文章
Java 大数据在智能教育在线实验室设备管理与实验资源优化配置中的应用实践
本文探讨Java大数据技术在智能教育在线实验室设备管理与资源优化中的应用。通过统一接入异构设备、构建四层实时处理管道及安全防护双体系,显著提升设备利用率与实验效率。某“双一流”高校实践显示,设备利用率从41%升至89%,等待时间缩短78%。该方案降低管理成本,为教育数字化转型提供技术支持。
51 0
|
23天前
|
Java 抽象类与接口在 Java17 + 开发中的现代应用实践解析
《Java抽象类与接口核心技术解析》 摘要:本文全面剖析Java抽象类与接口的核心概念与技术差异。抽象类通过模板设计实现代码复用,支持具体方法与状态管理;接口则定义行为规范,实现多态支持。文章详细对比了两者在实例化、方法实现、继承机制等方面的区别,并提供了模板方法模式(抽象类)和策略模式(接口)的典型应用示例。特别指出Java8+新特性为接口带来的灵活性提升,包括默认方法和静态方法。最后给出最佳实践建议:优先使用接口定义行为规范,通过抽象类实现代码复用,合理组合两者构建灵活架构。
38 2
现代应用场景中 Java 集合框架的核心技术与实践要点
本内容聚焦Java 17及最新技术趋势,通过实例解析Java集合框架的高级用法与性能优化。涵盖Record类简化数据模型、集合工厂方法创建不可变集合、HashMap初始容量调优、ConcurrentHashMap高效并发处理、Stream API复杂数据操作与并行流、TreeMap自定义排序等核心知识点。同时引入JMH微基准测试与VisualVM工具分析性能,总结现代集合框架最佳实践,如泛型使用、合适集合类型选择及线程安全策略。结合实际案例,助你深入掌握Java集合框架的高效应用与优化技巧。
70 4
Java 大视界 -- Java 大数据机器学习模型在金融衍生品定价中的创新方法与实践(166)
本文围绕 Java 大数据机器学习模型在金融衍生品定价中的应用展开,分析定价现状与挑战,阐述技术原理与应用,结合真实案例与代码给出实操方案,助力提升金融衍生品定价的准确性与效率。
Java 大视界 -- Java 大数据机器学习模型在金融衍生品定价中的创新方法与实践(166)
从理论到实践:使用JAVA实现RAG、Agent、微调等六种常见大模型定制策略
大语言模型(LLM)在过去几年中彻底改变了自然语言处理领域,展现了在理解和生成类人文本方面的卓越能力。然而,通用LLM的开箱即用性能并不总能满足特定的业务需求或领域要求。为了将LLM更好地应用于实际场景,开发出了多种LLM定制策略。本文将深入探讨RAG(Retrieval Augmented Generation)、Agent、微调(Fine-Tuning)等六种常见的大模型定制策略,并使用JAVA进行demo处理,以期为AI资深架构师提供实践指导。
458 73
【Java进阶】JavaScript电灯开关实例:从理论到实践
这个例子展示了JavaScript的基本功能,包括操作HTML元素,监听事件,以及改变元素的样式。通过学习和理解这个例子,你可以了解到JavaScript在网页中的应用,以及如何使用JavaScript来创建交互式的网页。
70 13
|
8月前
|
Java内存模型深度解析:从理论到实践####
【10月更文挑战第21天】 本文深入探讨了Java内存模型(JMM)的核心概念与底层机制,通过剖析其设计原理、内存可见性问题及其解决方案,结合具体代码示例,帮助读者构建对JMM的全面理解。不同于传统的摘要概述,我们将直接以故事化手法引入,让读者在轻松的情境中领略JMM的精髓。 ####
110 6
深入理解Java内存模型与并发编程####
本文旨在探讨Java内存模型(JMM)的复杂性及其对并发编程的影响,不同于传统的摘要形式,本文将以一个实际案例为引子,逐步揭示JMM的核心概念,包括原子性、可见性、有序性,以及这些特性在多线程环境下的具体表现。通过对比分析不同并发工具类的应用,如synchronized、volatile关键字、Lock接口及其实现等,本文将展示如何在实践中有效利用JMM来设计高效且安全的并发程序。最后,还将简要介绍Java 8及更高版本中引入的新特性,如StampedLock,以及它们如何进一步优化多线程编程模型。 ####
101 0
拥抱 OpenTelemetry:阿里云 Java Agent 演进实践
拥抱 OpenTelemetry:阿里云 Java Agent 演进实践
160 0
小团队 CI/CD 实践:无需运维,Java Web应用的自动化部署
本文介绍如何使用GitHub Actions和阿里云Kubernetes(ACK)实现Java Web应用的自动化部署。通过CI/CD流程,开发人员无需手动处理复杂的运维任务,从而提高效率并减少错误。文中详细讲解了Docker与Kubernetes的概念,并演示了从创建Kubernetes集群、配置容器镜像服务到设置GitHub仓库Secrets及编写GitHub Actions工作流的具体步骤。最终实现了代码提交后自动构建、推送镜像并部署到Kubernetes集群的功能。整个过程不仅简化了部署流程,还确保了应用在不同环境中的稳定运行。
277 9
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等