简介
在当今高并发的互联网环境中,Java并发编程已成为开发者必须掌握的核心技能。本文将从基础概念出发,深入讲解Java并发编程的核心技术与企业级开发实践,结合最新Java 21特性(如结构化并发编程),通过代码实战与性能调优技巧,帮助开发者系统性地掌握多线程开发能力。文章涵盖线程管理、锁机制、线程池优化、并发工具类、分布式锁及限流算法等核心内容,并提供完整的开发步骤与代码示例,助力开发者从零到一构建健壮的高并发系统。
一、Java并发编程基础概念
1. 线程与进程的区别
在Java中,线程(Thread)是程序执行的最小单元,而进程(Process)是资源分配的基本单位。一个进程可以包含多个线程,线程共享进程的内存空间(堆内存、方法区等),但每个线程拥有独立的程序计数器和虚拟机栈。这种设计使得线程间的通信更高效,但也引入了线程安全问题。
代码示例:创建线程的两种方式
// 方式1:继承Thread类
class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程ID: " + Thread.currentThread().getId());
}
}
// 方式2:实现Runnable接口
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("任务线程ID: " + Thread.currentThread().getId());
}
}
public class ThreadDemo {
public static void main(String[] args) {
MyThread thread1 = new MyThread();
Thread thread2 = new Thread(new MyRunnable());
thread1.start();
thread2.start();
}
}
2. 线程生命周期与状态
Java线程的生命周期包括以下状态:
- New(新建):线程对象被创建,尚未启动。
- Runnable(可运行):线程被调度,等待CPU分配时间片。
- Blocked(阻塞):因锁资源或等待I/O而暂停。
- Waiting/Timed Waiting(等待/超时等待):等待其他线程通知或超时。
- Terminated(终止):线程执行完毕或被强制中断。
代码示例:线程状态监控
public class ThreadStateDemo {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000); // 进入Timed Waiting状态
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("线程状态(启动前): " + thread.getState());
thread.start();
System.out.println("线程状态(运行中): " + thread.getState());
try {
thread.join(); // 等待线程结束
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程状态(终止后): " + thread.getState());
}
}
3. 并发编程的核心挑战
并发编程的复杂性主要体现在以下方面:
- 线程安全问题:多个线程同时访问共享资源可能导致数据不一致。
- 死锁:线程间相互等待对方释放资源,导致程序停滞。
- 资源竞争:线程对共享资源的争夺可能引发性能瓶颈。
代码示例:模拟线程安全问题
class Counter {
private int count = 0;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class ThreadSafetyDemo {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("最终计数结果: " + counter.getCount()); // 预期为2000,实际可能小于该值
}
}
二、Java并发编程核心技术
1. 线程池:高效管理并发任务
线程池通过复用线程减少线程创建和销毁的开销,提升系统性能。Java提供了ExecutorService和ThreadPoolExecutor类来管理线程池。
代码示例:线程池配置与使用
import java.util.concurrent.*;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 创建线程池
ExecutorService executor = new ThreadPoolExecutor(
2, // 核心线程数
4, // 最大线程数
60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100), // 任务队列
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
// 提交任务
for (int i = 0; i < 10; i++) {
executor.submit(() -> {
System.out.println("任务由线程: " + Thread.currentThread().getName() + " 执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
// 关闭线程池
executor.shutdown();
}
}
2. 锁机制:保障线程安全
Java提供了多种锁机制,包括synchronized、ReentrantLock和StampedLock。
代码示例:使用ReentrantLock实现线程安全
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class SafeCounter {
private int count = 0;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
return count;
}
}
public class LockDemo {
public static void main(String[] args) throws InterruptedException {
SafeCounter counter = new SafeCounter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("最终计数结果: " + counter.getCount()); // 保证输出为2000
}
}
3. 并发工具类:简化复杂场景
Java并发工具类(如CountDownLatch、CyclicBarrier、Semaphore)可简化多线程协作场景。
代码示例:使用CountDownLatch同步线程
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
int threadCount = 3;
CountDownLatch latch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 正在执行任务");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown(); // 任务完成后减少计数
}).start();
}
latch.await(); // 等待所有线程完成
System.out.println("所有任务已完成");
}
}
三、Java并发编程企业级开发实践
1. 高性能线程池调优
在企业级应用中,合理配置线程池参数是提升性能的关键。
代码示例:动态调整线程池参数
import java.util.concurrent.*;
public class ThreadPoolTuning {
public static void main(String[] args) {
int corePoolSize = Runtime.getRuntime().availableProcessors(); // 核心线程数等于CPU核心数
int maxPoolSize = corePoolSize * 2; // 最大线程数为CPU核心数的两倍
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(1000); // 任务队列
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy(); // 拒绝策略
ExecutorService executor = new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
60, TimeUnit.SECONDS,
workQueue,
handler
);
// 提交任务
for (int i = 0; i < 1000; i++) {
executor.submit(() -> {
// 模拟任务
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
}
}
2. 分布式锁:解决跨服务并发问题
在分布式系统中,传统锁机制无法跨服务生效,需借助分布式锁(如Redis或ZooKeeper)。
代码示例:基于Redis的分布式锁
import redis.clients.jedis.Jedis;
public class DistributedLock {
private static final String LOCK_KEY = "distributed_lock";
private static final int EXPIRE_TIME = 30000; // 锁过期时间(毫秒)
public static boolean acquireLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
return "OK".equals(result);
}
public static void releaseLock(Jedis jedis, String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
jedis.eval(script, 1, lockKey, requestId);
}
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
String requestId = "123"; // 唯一标识符
if (acquireLock(jedis, LOCK_KEY, requestId, EXPIRE_TIME)) {
try {
// 执行业务逻辑
System.out.println("成功获取分布式锁");
} finally {
releaseLock(jedis, LOCK_KEY, requestId);
System.out.println("释放分布式锁");
}
} else {
System.out.println("未能获取分布式锁");
}
}
}
3. 限流算法:保护系统稳定性
在高并发场景中,限流算法(如令牌桶、漏桶)可防止系统过载。
代码示例:基于令牌桶算法的限流器
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
public class TokenBucketRateLimiter {
private final int capacity; // 桶容量
private final int refillRate; // 补充速率(每秒)
private final AtomicInteger tokens; // 当前令牌数
private final long lastRefillTime;
private final ReentrantLock lock = new ReentrantLock();
public TokenBucketRateLimiter(int capacity, int refillRate) {
this.capacity = capacity;
this.refillRate = refillRate;
this.tokens = new AtomicInteger(capacity);
this.lastRefillTime = System.currentTimeMillis();
}
public boolean tryConsume() {
lock.lock();
try {
long now = System.currentTimeMillis();
long timeElapsed = now - lastRefillTime;
int newTokens = (int) (timeElapsed * refillRate / 1000); // 计算新增令牌数
int currentTokens = tokens.get();
currentTokens = Math.min(currentTokens + newTokens, capacity);
tokens.set(currentTokens);
lastRefillTime = now;
if (tokens.get() >= 1) {
tokens.decrementAndGet();
return true;
}
return false;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
TokenBucketRateLimiter limiter = new TokenBucketRateLimiter(10, 5); // 容量10,速率5/s
for (int i = 0; i < 15; i++) {
if (limiter.tryConsume()) {
System.out.println("请求通过");
} else {
System.out.println("请求被限流");
}
try {
Thread.sleep(200); // 模拟请求间隔
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
四、Java 21新特性:结构化并发编程
1. 结构化并发的核心理念
Java 21引入的结构化并发编程(Structured Concurrency)通过StructuredTaskScope类简化并发任务的管理,解决传统并发编程中的生命周期难以追踪、异常处理复杂等问题。
代码示例:使用StructuredTaskScope协调并发任务
import java.util.concurrent.*;
public class StructuredConcurrencyDemo {
public static void main(String[] args) throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> userFuture = scope.fork(() -> findUser());
Future<Integer> orderFuture = scope.fork(() -> fetchOrder());
scope.join(); // 等待所有任务完成
scope.throwIfFailed(); // 抛出子任务异常
String user = userFuture.resultNow();
Integer order = orderFuture.resultNow();
System.out.println("用户: " + user + ", 订单号: " + order);
}
}
private static String findUser() throws InterruptedException {
Thread.sleep(1000);
return "JohnDoe";
}
private static Integer fetchOrder() throws InterruptedException {
Thread.sleep(1500);
return 123456;
}
}
2. 结构化并发的优势
- 任务生命周期管理:子任务的生命周期与父任务绑定,确保资源自动释放。
- 异常传播:子任务的异常会自动传播到父任务,简化错误处理。
- 代码结构清晰:通过
try-with-resources模式管理任务作用域,提升可读性。
五、总结
Java并发编程是构建高并发系统的核心技能,本文从基础概念到企业级开发实践,系统性地讲解了线程管理、锁机制、线程池优化、并发工具类、分布式锁及限流算法,并结合Java 21的结构化并发编程特性提供了代码实战。通过学习本文,开发者可掌握从零到一构建健壮高并发系统的完整路径。