成神之路的博客 成神之路的博客
首页
Java进阶
常用框架
架构设计
AI探索
Python
大数据
工具资源
关于博主
GitHub (opens new window)
首页
Java进阶
常用框架
架构设计
AI探索
Python
大数据
工具资源
关于博主
GitHub (opens new window)
  • 设计模式

  • 集合

  • 并发编程

    • Java并发编程实战
      • 前言
      • Java并发编程基础
        • 线程的生命周期
        • 线程的创建方式
      • 并发编程的挑战
        • 线程安全问题
        • 死锁
      • Java并发工具类
        • 同步容器
        • 锁机制
      • 线程池最佳实践
        • 线程池的创建
        • 线程池的关闭
      • 案例分析:高并发订单系统优化
        • 问题描述
        • 优化方案
        • 优化效果
      • 总结与建议
  • 性能优化

  • Java
  • 并发编程
starxu
2023-11-05
目录

Java并发编程实战

# Java并发编程实战

# 前言

随着多核处理器的普及,并发编程变得越来越重要。良好的并发设计可以充分利用系统资源,提高程序性能。本文将分享Java并发编程的核心概念、常见问题及实战经验。

# Java并发编程基础

# 线程的生命周期

Java线程的生命周期包括以下状态:

  • NEW:新创建的线程,尚未启动
  • RUNNABLE:可运行状态,包括就绪和运行中
  • BLOCKED:阻塞状态,等待获取锁
  • WAITING:等待状态,无限期等待另一个线程的特定操作
  • TIMED_WAITING:超时等待状态,在指定时间内等待
  • TERMINATED:终止状态,线程执行完毕

# 线程的创建方式

Java中创建线程的几种方式:

// 1. 继承Thread类
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread running...");
    }
}
// 使用:new MyThread().start();

// 2. 实现Runnable接口
Runnable task = () -> System.out.println("Runnable task running...");
// 使用:new Thread(task).start();

// 3. 实现Callable接口(可返回结果)
Callable<String> call = () -> {
    return "Callable result";
};
FutureTask<String> future = new FutureTask<>(call);
// 使用:new Thread(future).start(); String result = future.get();

// 4. 使用线程池
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(() -> System.out.println("Task in thread pool"));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 并发编程的挑战

# 线程安全问题

在多线程环境下,共享变量的并发访问可能导致数据不一致:

// 非线程安全的计数器
public class Counter {
    private int count = 0;
    
    public void increment() {
        count++; // 非原子操作
    }
    
    public int getCount() {
        return count;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 死锁

当两个或多个线程互相等待对方持有的锁时,会发生死锁:

public void deadlockDemo() {
    Object lock1 = new Object();
    Object lock2 = new Object();
    
    Thread t1 = new Thread(() -> {
        synchronized(lock1) {
            sleep(100); // 确保线程2有机会获取lock2
            synchronized(lock2) {
                System.out.println("Thread 1 acquired both locks");
            }
        }
    });
    
    Thread t2 = new Thread(() -> {
        synchronized(lock2) {
            sleep(100);
            synchronized(lock1) {
                System.out.println("Thread 2 acquired both locks");
            }
        }
    });
    
    t1.start();
    t2.start();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# Java并发工具类

# 同步容器

Java提供了多种线程安全的集合类:

// 线程安全的List
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
List<String> concurrentList = new CopyOnWriteArrayList<>();

// 线程安全的Map
Map<String, String> synchronizedMap = Collections.synchronizedMap(new HashMap<>());
Map<String, String> concurrentMap = new ConcurrentHashMap<>();

// 线程安全的Set
Set<String> synchronizedSet = Collections.synchronizedSet(new HashSet<>());
Set<String> concurrentSet = new CopyOnWriteArraySet<>();
1
2
3
4
5
6
7
8
9
10
11

# 锁机制

Java提供了多种锁机制:

// ReentrantLock
ReentrantLock lock = new ReentrantLock();
try {
    lock.lock();
    // 临界区代码
} finally {
    lock.unlock(); // 确保锁被释放
}

// ReadWriteLock
ReadWriteLock rwLock = new ReentrantReadWriteLock();
// 读操作,允许并发
rwLock.readLock().lock();
try {
    // 读取共享数据
} finally {
    rwLock.readLock().unlock();
}
// 写操作,独占锁
rwLock.writeLock().lock();
try {
    // 修改共享数据
} finally {
    rwLock.writeLock().unlock();
}

// StampedLock(Java 8)
StampedLock lock = new StampedLock();
// 乐观读
long stamp = lock.tryOptimisticRead();
// 读取数据
if (!lock.validate(stamp)) {
    // 数据已被修改,转为悲观读
    stamp = lock.readLock();
    try {
        // 重新读取数据
    } finally {
        lock.unlockRead(stamp);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 线程池最佳实践

# 线程池的创建

推荐使用ThreadPoolExecutor自定义线程池,而不是Executors工厂方法:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    5,                      // 核心线程数
    10,                     // 最大线程数
    60L, TimeUnit.SECONDS,  // 空闲线程存活时间
    new ArrayBlockingQueue<>(100), // 工作队列
    new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
1
2
3
4
5
6
7

# 线程池的关闭

正确关闭线程池:

executor.shutdown(); // 平滑关闭,等待任务完成
boolean terminated = executor.awaitTermination(30, TimeUnit.SECONDS);
if (!terminated) {
    executor.shutdownNow(); // 强制关闭
}
1
2
3
4
5

# 案例分析:高并发订单系统优化

# 问题描述

某电商平台订单系统在秒杀活动期间出现严重性能问题:

  • 系统响应缓慢
  • 数据库连接耗尽
  • 部分订单处理失败

# 优化方案

  1. 使用线程池处理订单:
// 创建合适大小的线程池
ThreadPoolExecutor orderExecutor = new ThreadPoolExecutor(
    10, 20, 60L, TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(500),
    new ThreadPoolExecutor.CallerRunsPolicy()
);

// 异步处理订单
public void processOrder(Order order) {
    orderExecutor.submit(() -> {
        try {
            // 订单处理逻辑
            saveOrder(order);
            notifyPayment(order);
        } catch (Exception e) {
            // 异常处理
            logError(e);
            retryQueue.add(order);
        }
    });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  1. 使用读写锁优化库存查询:
public class InventoryService {
    private Map<Long, Integer> inventory = new ConcurrentHashMap<>();
    private ReadWriteLock lock = new ReentrantReadWriteLock();
    
    public Integer getStock(Long productId) {
        lock.readLock().lock();
        try {
            return inventory.get(productId);
        } finally {
            lock.readLock().unlock();
        }
    }
    
    public void updateStock(Long productId, int delta) {
        lock.writeLock().lock();
        try {
            Integer current = inventory.getOrDefault(productId, 0);
            inventory.put(productId, current + delta);
        } finally {
            lock.writeLock().unlock();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  1. 使用CompletableFuture并行处理订单步骤:
public CompletableFuture<Order> processOrderAsync(Order order) {
    return CompletableFuture.supplyAsync(() -> {
        // 验证订单
        validateOrder(order);
        return order;
    }).thenApplyAsync(validOrder -> {
        // 扣减库存
        reduceInventory(validOrder);
        return validOrder;
    }).thenApplyAsync(validOrder -> {
        // 生成支付信息
        createPayment(validOrder);
        return validOrder;
    }).exceptionally(ex -> {
        // 异常处理
        handleOrderException(order, ex);
        return null;
    });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 优化效果

  • 系统吞吐量提升300%
  • 平均响应时间从1.2秒降至0.3秒
  • 订单处理成功率从92%提升至99.9%

# 总结与建议

  1. 合理使用线程池:根据业务特点和硬件资源配置合适的线程池参数
  2. 选择合适的并发工具:针对不同场景选择合适的并发容器和同步工具
  3. 避免过度同步:同步会带来性能开销,只在必要时使用
  4. 防止死锁:合理设计锁的获取顺序,使用带超时的锁获取方法
  5. 优化锁粒度:减小锁的范围,提高并发度
  6. 使用无锁算法:在适当场景下使用CAS等无锁算法提高性能

Java并发编程是一个复杂的主题,需要不断学习和实践。希望本文能为你的并发编程之路提供一些帮助。

上次更新: 2025/07/01, 01:17:09
ArrayList源码分析
JVM性能调优实战

← ArrayList源码分析 JVM性能调优实战→

最近更新
01
单例模式
03-11
02
SpringCloud微服务实战
12-10
03
JVM性能调优实战
10-15
更多文章>
Theme by Vdoing | Copyright © 2023-2025 star Xu | MIT License | xxxxx号 | xxxxxx
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式