Skip to content

并发编程常用写法 ​

并发编程是Java开发中的重要技能。本文详细介绍并发编程的常用写法和最佳实践,包含线程池、锁、并发集合等。

📋 目录 ​

🎯 一、线程池使用 ​

1.1 创建线程池 ​

使用Executors(简单场景):

java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

// 固定大小线程池
ExecutorService executor1 = Executors.newFixedThreadPool(10);

// 缓存线程池
ExecutorService executor2 = Executors.newCachedThreadPool();

// 单线程池
ExecutorService executor3 = Executors.newSingleThreadExecutor();

// 定时任务线程池
ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(5);

使用ThreadPoolExecutor(推荐):

java
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.LinkedBlockingQueue;

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    5,                              // 核心线程数
    10,                             // 最大线程数
    60L,                            // 空闲线程存活时间
    TimeUnit.SECONDS,               // 时间单位
    new LinkedBlockingQueue<>(100), // 工作队列
    new ThreadFactory() {           // 线程工厂
        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r, "my-thread-" + System.currentTimeMillis());
            t.setDaemon(false);
            return t;
        }
    },
    new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);

1.2 提交任务 ​

提交任务:

java
ExecutorService executor = Executors.newFixedThreadPool(10);

// 提交Runnable任务
executor.submit(() -> {
    System.out.println("执行任务");
});

// 提交Callable任务
Future<String> future = executor.submit(() -> {
    Thread.sleep(1000);
    return "任务完成";
});

// 获取结果
try {
    String result = future.get();  // 阻塞等待结果
    String result2 = future.get(5, TimeUnit.SECONDS);  // 带超时
} catch (Exception e) {
    // 处理异常
}

// 批量提交任务
List<Callable<String>> tasks = Arrays.asList(
    () -> "任务1",
    () -> "任务2",
    () -> "任务3"
);
List<Future<String>> futures = executor.invokeAll(tasks);

1.3 线程池关闭 ​

关闭线程池:

java
// 优雅关闭
executor.shutdown();  // 不接受新任务,等待已有任务完成

try {
    if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
        executor.shutdownNow();  // 强制关闭
        if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
            System.err.println("线程池未正常关闭");
        }
    }
} catch (InterruptedException e) {
    executor.shutdownNow();
    Thread.currentThread().interrupt();
}

🎯 二、锁机制 ​

2.1 synchronized ​

synchronized使用:

java
// 同步方法
public synchronized void method() {
    // 同步代码块
}

// 同步代码块
public void method() {
    synchronized (this) {
        // 同步代码
    }
}

// 同步类方法
public static synchronized void staticMethod() {
    // 同步静态方法
}

// 同步类对象
public void method() {
    synchronized (MyClass.class) {
        // 同步代码
    }
}

2.2 ReentrantLock ​

ReentrantLock使用:

java
import java.util.concurrent.locks.ReentrantLock;

private final ReentrantLock lock = new ReentrantLock();

public void method() {
    lock.lock();
    try {
        // 临界区代码
    } finally {
        lock.unlock();  // 确保锁被释放
    }
}

// 可中断锁
public void interruptibleMethod() throws InterruptedException {
    lock.lockInterruptibly();
    try {
        // 临界区代码
    } finally {
        lock.unlock();
    }
}

// 尝试获取锁
public boolean tryLockMethod() {
    if (lock.tryLock()) {
        try {
            // 临界区代码
            return true;
        } finally {
            lock.unlock();
        }
    }
    return false;
}

// 带超时的尝试获取锁
public boolean tryLockWithTimeout() throws InterruptedException {
    if (lock.tryLock(5, TimeUnit.SECONDS)) {
        try {
            // 临界区代码
            return true;
        } finally {
            lock.unlock();
        }
    }
    return false;
}

2.3 ReadWriteLock ​

读写锁:

java
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
private final ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();

// 读操作
public String read() {
    readLock.lock();
    try {
        // 读操作(可并发)
        return data;
    } finally {
        readLock.unlock();
    }
}

// 写操作
public void write(String value) {
    writeLock.lock();
    try {
        // 写操作(互斥)
        data = value;
    } finally {
        writeLock.unlock();
    }
}

🎯 三、并发集合 ​

3.1 并发集合使用 ​

ConcurrentHashMap:

java
import java.util.concurrent.ConcurrentHashMap;

ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

// 基本操作
map.put("key", 1);
Integer value = map.get("key");
map.remove("key");

// 原子操作
map.putIfAbsent("key", 1);  // 如果不存在才放入
map.replace("key", 1, 2);   // 如果值为1才替换为2
map.compute("key", (k, v) -> v == null ? 1 : v + 1);

// 遍历(弱一致性)
map.forEach((key, value) -> System.out.println(key + "=" + value));

CopyOnWriteArrayList:

java
import java.util.concurrent.CopyOnWriteArrayList;

CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();

// 基本操作
list.add("a");
list.get(0);
list.remove(0);

// 遍历(不会抛出ConcurrentModificationException)
for (String item : list) {
    // 安全遍历
}

BlockingQueue:

java
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

BlockingQueue<String> queue = new LinkedBlockingQueue<>(100);

// 添加元素(阻塞)
queue.put("item");  // 队列满时阻塞

// 获取元素(阻塞)
String item = queue.take();  // 队列空时阻塞

// 非阻塞操作
boolean added = queue.offer("item");  // 返回是否成功
String item2 = queue.poll();          // 返回元素或null

// 带超时的操作
boolean added2 = queue.offer("item", 5, TimeUnit.SECONDS);
String item3 = queue.poll(5, TimeUnit.SECONDS);

🎯 四、原子类 ​

4.1 原子类使用 ​

AtomicInteger:

java
import java.util.concurrent.atomic.AtomicInteger;

AtomicInteger counter = new AtomicInteger(0);

// 基本操作
counter.incrementAndGet();    // 先加1再返回
counter.getAndIncrement();    // 先返回再加1
counter.addAndGet(10);        // 加10后返回
counter.getAndAdd(10);        // 先返回再加10

// 比较并设置
boolean success = counter.compareAndSet(0, 10);  // 如果当前值为0,则设置为10

// 获取并更新
int oldValue = counter.getAndUpdate(x -> x * 2);

// 更新并获取
int newValue = counter.updateAndGet(x -> x + 1);

AtomicLong:

java
import java.util.concurrent.atomic.AtomicLong;

AtomicLong counter = new AtomicLong(0L);

// 与AtomicInteger类似的操作
counter.incrementAndGet();
counter.compareAndSet(0L, 100L);

AtomicReference:

java
import java.util.concurrent.atomic.AtomicReference;

AtomicReference<String> reference = new AtomicReference<>("初始值");

// 获取和设置
String value = reference.get();
reference.set("新值");

// 比较并设置
boolean success = reference.compareAndSet("初始值", "新值");

// 获取并更新
String oldValue = reference.getAndUpdate(s -> s + "更新");

📖 学习资源 ​

官方文档 ​

书籍推荐 ​

  • 《Java并发编程实战》 - Brian Goetz

✅ 学习检查清单 ​

  • [ ] 已掌握线程池的使用
  • [ ] 已掌握锁机制
  • [ ] 已熟悉并发集合
  • [ ] 已了解原子类的使用

上一章节:IO操作常用写法
下一章节:命名规范
返回目录:代码规范