Files
2026-01-15 11:53:37 +08:00

5.9 KiB
Raw Permalink Blame History

并发编程

目录


并发概念

并发 vs 并行

// 并发:同一时间段内多个任务交替执行
// 单核 CPU时间片轮转

// 并行:同一时刻多个任务同时执行
// 多核 CPU真正同时执行

并发问题

// 问题1竞态条件
private int count = 0;

public void increment() {
    count++; // 非原子操作
    // 1. 读取 count
    // 2. count + 1
    // 3. 写入 count
    // 多线程同时执行可能导致数据错误
}

// 问题2可见性问题
private boolean flag = false;

// 线程1
flag = true;

// 线程2
while (!flag) {
    // 可能永远循环(可见性问题)
}

同步与异步

同步

// 同步:按顺序执行,等待结果
public void syncMethod() {
    String result = loadData(); // 等待加载完成
    updateUI(result);
}

异步

// 异步:不等待结果,继续执行
public void asyncMethod() {
    loadDataAsync(new Callback() {
        @Override
        public void onResult(String result) {
            updateUI(result);
        }
    });
    // 继续执行其他代码
}

锁机制

synchronized

// 同步方法
public synchronized void method() {
    // 临界区代码
}

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

// 同步静态方法
public static synchronized void staticMethod() {
    // 临界区代码
}

ReentrantLock

// ReentrantLock可重入锁
private Lock lock = new ReentrantLock();

public void method() {
    lock.lock();
    try {
        // 临界区代码
    } finally {
        lock.unlock();
    }
}

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

ReadWriteLock

// ReadWriteLock读写锁
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private Lock readLock = readWriteLock.readLock();
private Lock writeLock = readWriteLock.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();
    }
}

原子类

AtomicInteger

// AtomicInteger原子整数
private AtomicInteger count = new AtomicInteger(0);

// 原子操作
count.incrementAndGet(); // 原子递增
count.getAndIncrement(); // 先获取再递增
count.addAndGet(10);     // 原子加法

AtomicReference

// AtomicReference原子引用
private AtomicReference<String> ref = new AtomicReference<>("initial");

// 原子更新
ref.compareAndSet("initial", "new"); // CAS 操作

CAS 操作

// CASCompare And Swap
// 比较并交换
// 如果当前值等于期望值,则更新为新值

// 实现
public boolean compareAndSet(int expect, int update) {
    if (value == expect) {
        value = update;
        return true;
    }
    return false;
}

并发集合

ConcurrentHashMap

// ConcurrentHashMap线程安全的 HashMap
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
map.put("key", "value");
String value = map.get("key");

// 特点:
// - 分段锁机制
// - 支持并发读写
// - 性能优于 Hashtable

CopyOnWriteArrayList

// CopyOnWriteArrayList线程安全的 ArrayList
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("item");
String item = list.get(0);

// 特点:
// - 写时复制
// - 读操作无锁
// - 适合读多写少场景

BlockingQueue

// BlockingQueue阻塞队列
BlockingQueue<String> queue = new LinkedBlockingQueue<>();

// 生产者
queue.put("item"); // 阻塞直到有空间

// 消费者
String item = queue.take(); // 阻塞直到有元素

并发编程最佳实践

1. 避免死锁

// ❌ 问题:可能死锁
synchronized (lock1) {
    synchronized (lock2) {
        // 代码
    }
}

// 另一个线程
synchronized (lock2) {
    synchronized (lock1) {
        // 代码
    }
}

// ✅ 解决:按相同顺序获取锁
synchronized (lock1) {
    synchronized (lock2) {
        // 代码
    }
}

2. 使用并发集合

// ✅ 使用并发集合
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();

// ❌ 使用同步包装
Map<String, String> map = Collections.synchronizedMap(new HashMap<>());

3. 最小化锁范围

// ✅ 最小化锁范围
public void method() {
    // 不需要同步的代码
    synchronized (this) {
        // 需要同步的代码
    }
    // 不需要同步的代码
}

// ❌ 扩大锁范围
public synchronized void method() {
    // 所有代码都在锁内
}

面试常见问题

Q1: 并发和并行的区别?

答案:

  • 并发:同一时间段内多个任务交替执行
  • 并行:同一时刻多个任务同时执行

Q2: 并发问题有哪些?

答案:

  1. 竞态条件:多线程同时修改共享数据
  2. 可见性问题:线程修改数据其他线程看不到
  3. 死锁:多个线程互相等待

Q3: synchronized 和 Lock 的区别?

答案:

  • synchronizedJVM 层面,自动释放锁
  • LockAPI 层面,手动释放锁,更灵活

Q4: CAS 操作?

答案:

  • Compare And Swap比较并交换
  • 原子操作,无锁编程
  • 如果当前值等于期望值,则更新

Q5: 并发集合有哪些?

答案:

  1. ConcurrentHashMap线程安全的 HashMap
  2. CopyOnWriteArrayList线程安全的 ArrayList
  3. BlockingQueue阻塞队列

最后更新2024年