Java并发编程:从基础到高级应用
立即解锁
发布时间: 2025-08-18 00:34:30 阅读量: 2 订阅数: 4 

### Java并发编程:从基础到高级应用
#### 1. 同步与线程安全
在Java编程中,同步是一个关键概念,它能确保多线程环境下的数据一致性和程序的正确性。但过度同步会导致性能下降,所以需要谨慎使用。
当一个方法修改静态字段,且该方法可能被多个线程调用时,必须在内部对该字段的访问进行同步,除非类能够容忍不确定的行为。因为即使该字段是私有的,它本质上也是一个全局变量,可能被无关的客户端读取和修改。
为避免死锁和数据损坏,不要在同步区域内调用外部方法。在设计可变类时,要考虑是否需要进行内部同步。在多核时代,避免过度同步尤为重要,只有在有充分理由时才进行内部同步,并清晰地记录决策。
#### 2. 优先使用执行器、任务和流而非线程
在早期,编写简单的工作队列代码复杂且容易出错。但随着Java的发展,`java.util.concurrent` 包引入了执行器框架(Executor Framework),极大地简化了任务的执行和管理。
以下是使用执行器框架的基本操作:
- **创建单线程执行器**:
```java
ExecutorService exec = Executors.newSingleThreadExecutor();
```
- **提交任务执行**:
```java
exec.execute(runnable);
```
- **优雅地终止执行器**:
```java
exec.shutdown();
```
执行器服务还提供了许多其他功能,如等待特定任务完成、等待一组任务完成、获取任务结果等。
线程池是执行器框架的一种重要形式,可以创建固定数量或可变数量线程的线程池。对于小型程序或轻负载服务器,`Executors.newCachedThreadPool` 通常是一个不错的选择;但对于高负载的生产服务器,`Executors.newFixedThreadPool` 或直接使用 `ThreadPoolExecutor` 类能提供更好的控制。
在Java 7中,执行器框架扩展支持了分叉 - 合并任务(fork - join tasks),由分叉 - 合并池(fork - join pool)执行。分叉 - 合并任务可以拆分为更小的子任务,提高CPU利用率、吞吐量和降低延迟。并行流(parallel streams)基于分叉 - 合并池构建,能轻松利用其性能优势。
#### 3. 优先使用并发工具而非 `wait` 和 `notify`
自Java 5以来,平台提供了更高级的并发工具,减少了使用 `wait` 和 `notify` 的必要性。`java.util.concurrent` 包中的并发工具分为执行器框架、并发集合和同步器三类。
并发集合是标准集合接口的高性能并发实现,如 `List`、`Queue` 和 `Map`。它们内部管理同步,不适合外部加锁。为了支持原子操作,并发集合接口提供了状态依赖的修改操作。例如,`ConcurrentHashMap` 的 `putIfAbsent` 方法可以实现线程安全的规范化映射:
```java
// Concurrent canonicalizing map atop ConcurrentMap - not optimal
private static final ConcurrentMap<String, String> map = new ConcurrentHashMap<>();
public static String intern(String s) {
String previousValue = map.putIfAbsent(s, s);
return previousValue == null ? s : previousValue;
}
```
优化后的代码:
```java
// Concurrent canonicalizing map atop ConcurrentMap - faster!
public static String intern(String s) {
String result = map.get(s);
if (result == null) {
result = map.putIfAbsent(s, s);
if (result == null)
result = s;
}
return result;
}
```
一些集合接口扩展了阻塞操作,如 `BlockingQueue`,可用于工作队列。同步器是允许线程相互等待、协调活动的对象,常见的同步器有 `CountDownLatch` 和 `Semaphore` 等。
以下是使用 `CountDownLatch` 实现并发执行计时的示例:
```java
// Simple framework for timing concurrent execution
public static long time(Executor executor, int concurrency, Runnable action) throws InterruptedException {
CountDownLatch ready = new CountDownLatch(concurrency);
CountDownLatch start = new CountDownLatch(1);
CountDownLatch done = new CountDownLatch(concurrency);
for (int i = 0; i < concurrency; i++) {
executor.execute(() -> {
ready.countDown(); // Tell timer we're ready
try {
start.await(); // Wait till peers are ready
action.run();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
done.countDown(); // Tell timer we're done
}
});
}
ready.await(); // Wait for all workers to be ready
long startNanos = System.nanoTime();
start.countDown(); // And they're off!
done.await(); // Wait for all workers to finish
return System.nanoTime() - startNanos;
}
```
#### 4. 线程安全的文档记录
类在多线程环境下的行为是与客户端契约的重要部分。如果不记录类的线程安全级别,用户可能会做出错误的假设,导致同步不足或过度同步。
线程安全有多个级别:
| 线程安全级别 | 描述 | 示例 |
| ---- | ---- | ---- |
| 不可变(
0
0
复制全文
相关推荐









