Java并发编程 | 8lovelife's life
0%

Java并发编程

随着摩尔定律的失效,现代计算机拥有越来越多的核心数,如何高效利用多核能力提升系统吞吐量、响应速度是非常关键的。在 Java 应用程序中实现安全、高效、可伸缩的并发编程是极其困难的,但仍有一些技巧可遵循

并发问题

所有的并发问题都可以归纳为如何协调对并发状态的访问。可变状态越少,越容易确保线程安全性

  • 域如果不需要可变,尽量声明为 final 类型
  • 不可变对象一定是线程安全的
  • 封装可以有效管理复杂性。例如:可以将同步机制维护在对象内部
  • 使用同一把锁保护同一个 不变性条件一组变量的值在某一时刻不会发生变化中的所有变量
  • 对复合操作加锁
  • 从多个线程中访问同一个未加锁的可变变量,程序肯定会出问题
  • 在设计过程中考虑线程安全问题,并文档化

关于Java线程内容可以到这里了解 Java线程基础并发与多线程

结构化

围绕“任务执行”来设计并发程序,可以简化开发过程,提供更好的并发维护

  1. 定义清晰的任务边界
  2. 把工作分解为一系列任务
  3. 任务封装为 FutureTask
  4. 将 FutureTask 提交给 Executor

Executor 框架将任务提交与执行策略解耦,支持不同类型的执行策略,使用 FutureTask 和 Executor 框架,可以帮助我们构建可取消的任务和服务

并发包

Java java.util.concurrent 中提供了非常多性能优秀的并发工具类,如:同步器、读写锁、原子变量等。在进行并发编程时,应该优先使用并发包中的工具

性能与可伸缩性

性能指标大概可以分为 运行速度处理能力 两大类

  • 运行速度:指定任务单元需要“多快”才能处理完成。例如:延迟时间、响应时间
  • 处理能力:一定的计算资源下能完成“多少”工作。例如:吞吐量、可伸缩性

对服务器应用来说,“多少”“多快” 更重要。在并发编程中,独占方式的资源锁是对可伸缩性的最主要威胁,因此可以通过减少锁的持有时间,降低锁的粒度,以及采用非独占锁(如:ReadWriteLock )或非阻塞锁(如:AtomicLong、ReentrantLock 等)来代替独占锁

可伸缩性是指:当增加计算资源时(CPU、内存、存储容量或I/O带宽),程序的吞吐量或者处理能力相应地提升

Amdahl’s Law

Amdahl 定律描述的是:在增加计算资源的情况下,程序在理论上能够实现最高加速比,这个值取决于程序中可并行组件与串行组件所占的比重。最高加速比的公式为:

$$\begin{equation*}
Speedup<=\frac{1}{F+\frac{(1-F)}{N}}
\end{equation*}$$

F:必须被执行的串行部分
1-F:并行执行部分
N:处理核心数
Speedup:问题规模不变的情况下,提升处理器并行能力后能提升多少系统性能

参考

Java并发编程实战

I never had a family. I wanted one though. - Léon

Léon