Java的并发工具类

173 阅读2分钟

对于Java常见的并发工具包,有以下五种分别有不同的应用场景:

  • CountDownLatch:适用于控制多个线程同时开始执行
  • Semaphore:适用于控制同时访问某个资源的线程数量
  • CyclicBarrier:适用于控制多个线程在某个点上同步
  • ReentrantLock:适用于控制多个线程对共享资源的访问
  • ConcurrentHashMap:适用于控制多个线程对共享Map的访问

下面以常见的秒杀场景为例:

  1. CountDownLatch:CountDownLatch用于控制多个线程同时开始执行,适用于秒杀商品场景中的多个用户同时抢购。当所有用户都准备好后,CountDownLatch会释放所有线程,让它们同时开始执行。
public class SeckillService {
    private CountDownLatch startSignal = new CountDownLatch(1);
    private CountDownLatch endSignal;

    public void seckill() throws InterruptedException {
        // 等待所有线程准备好
        startSignal.await();

        // TODO执行秒杀逻辑...

        // 通知其他线程秒杀已结束
        endSignal.countDown();
    }

    public void start(int threadCount) {
        endSignal = new CountDownLatch(threadCount);

        for (int i = 0; i < threadCount; i++) {
            new Thread(() -> {
                try {
                    seckill();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }

        // 通知所有线程准备好
        startSignal.countDown();

        try {
            // 等待所有线程执行完毕
            endSignal.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  1. Semaphore:Semaphore可用于控制同时访问某个资源的线程数量,适用于秒杀商品场景中的限流。当达到最大并发数时,Semaphore会阻塞后续的线程,直到有线程释放资源。
public class SeckillService {
    private Semaphore semaphore = new Semaphore(100);

    public void seckill() throws InterruptedException {
        // 获取许可证
        semaphore.acquire();

        // 执行秒杀逻辑

        // 释放许可证
        semaphore.release();
    }
}
  1. CyclicBarrier:CyclicBarrier可以用于控制多个线程在某个点上同步,适用于秒杀商品场景中的等待所有用户准备好后再开始抢购。当所有线程都到达指定点后,CyclicBarrier会释放所有线程,让它们继续执行。
public class SeckillService {
    private CyclicBarrier barrier = new CyclicBarrier(100);

    public void seckill() throws InterruptedException, BrokenBarrierException {
        // 等待所有线程准备好
        barrier.await();

        // 执行秒杀逻辑
    }
}
  1. ReentrantLock:ReentrantLock可以用于控制多个线程对共享资源的访问,适用于秒杀商品场景中的对商品库存的访问。当一个线程获取到锁后,其他线程需要等待该线程释放锁后才能访问共享资源。
public class SeckillService {
    private ReentrantLock lock = new ReentrantLock();

    public void seckill() throws InterruptedException {
        lock.lock();

        try {
            // 执行秒杀逻辑
        } finally {
            lock.unlock();
        }
    }
}
  1. ConcurrentHashMap:ConcurrentHashMap可以用于控制多个线程对共享Map的访问,适用于秒杀商品场景中的对用户抢购记录的访问。ConcurrentHashMap可以保证多个线程同时访问Map时的线程安全。
public class SeckillService {
    private ConcurrentHashMap<Long, Integer> map = new ConcurrentHashMap<>();

    public void seckill(long userId) {
        // 判断用户是否已经抢购过
        if (map.containsKey(userId)) {
            // 已经抢购过,直接返回
            return;
        }

        // 执行秒杀逻辑

        // 记录用户抢购记录
        map.put(userId, 1);
    }
}