Java并发编程-JUC包概览

JUC包概览

java.util.concurrent(简称 juc)包是 Java 提供的用于并发编程的工具包,包含了大量的并发工具、锁、同步器和集合,极大地简化了并发编程。以下是 juc 包中一些重要内容的详细解析:

1. 并发工具类

Executor 框架

1.1. Executor 接口
  • 定义:这是一个顶级接口,定义了执行任务的标准方法。
  • 方法void execute(Runnable command);
  • 作用:用于将任务提交给执行者执行。
1.2. ExecutorService 接口
  • 扩展:扩展了 Executor 接口,提供了管理终止和跟踪异步任务执行的功能。
  • 主要方法
    • void shutdown();:启动有序关闭,不接受新任务。
    • List<Runnable> shutdownNow();:尝试停止所有正在执行的任务,并返回等待执行的任务列表。
    • Future<?> submit(Runnable task);:提交一个 Runnable 任务,返回一个 Future 表示任务的状态。
    • Future<T> submit(Callable<T> task);:提交一个 Callable 任务,返回一个 Future 表示任务的状态和结果。
1.3. ScheduledExecutorService 接口
  • 扩展:扩展了 ExecutorService 接口,允许任务在延迟后或定期执行。
  • 主要方法
    • ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);:在给定延迟后执行任务。
    • ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);:以固定的周期执行任务。
    • ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);:在每次执行完任务后,等待给定延迟再执行任务。
1.4. ThreadPoolExecutor 类
  • 实现:一个强大的线程池实现类,允许定制线程池的行为。
  • 构造方法
    • ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue);
  • 主要参数
    • corePoolSize:核心线程数。
    • maximumPoolSize:最大线程数。
    • keepAliveTime:非核心线程的存活时间。
    • unit:时间单位。
    • workQueue:任务队列。
1.5. Executors 工厂类
  • 作用:用于创建各种常用的 ExecutorService 实现。
  • 常用方法
    • Executors.newFixedThreadPool(int nThreads);:创建一个固定线程数的线程池。
    • Executors.newCachedThreadPool();:创建一个可缓存的线程池。
    • Executors.newSingleThreadExecutor();:创建一个单线程的线程池。
    • Executors.newScheduledThreadPool(int corePoolSize);:创建一个支持定时及周期性任务执行的线程池。

示例代码

ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.submit(() -> System.out.println("Task executed"));
executorService.shutdown();

这个示例代码展示了如何使用 Executors 工厂类创建一个固定线程池,并提交一个任务执行,最后关闭线程池。

2. 同步器

  • CountDownLatch
    • 用于多个线程等待某些条件完成后再继续执行。
    • 示例:多个线程等待主线程完成某些初始化工作。
CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        try {
            // 模拟工作
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            latch.countDown();
        }
    }).start();
}
latch.await();  // 主线程等待
System.out.println("All threads have finished");
  • CyclicBarrier
    • 允许一组线程互相等待,直到所有线程都到达某个屏障点。
    • 示例:在并行计算中使用,所有线程必须同步完成某个阶段工作后才能进入下一个阶段。
int parties = 3;
CyclicBarrier barrier = new CyclicBarrier(parties, () -> System.out.println("All parties have arrived"));
for (int i = 0; i < parties; i++) {
    new Thread(() -> {
        try {
            Thread.sleep(1000);  // 模拟工作
            barrier.await();
        } catch (Exception e) {
            Thread.currentThread().interrupt();
        }
    }).start();
}
  • Phaser
  • 用途:Phaser 是一个多阶段的栅栏,相当于 CyclicBarrier 的升级版,可用于分阶段任务的并发控制执行。
  • 主要方法
    • int register();:增加一个任务数,返回当前阶段号。
    • int arrive();:到达当前阶段,不等待其他线程。
    • int arriveAndAwaitAdvance();:到达当前阶段,并等待其他线程到达。
    • int arriveAndDeregister();:到达当前阶段,并减少一个任务数。
  • 示例
Phaser phaser = new Phaser(1); // 注册主线程
for (int i = 0; i < 3; i++) {
    phaser.register(); // 注册子线程
    new Thread(() -> {
        System.out.println(Thread.currentThread().getName() + " 开始阶段 1");
        phaser.arriveAndAwaitAdvance(); // 阶段 1 完成
        System.out.println(Thread.currentThread().getName() + " 开始阶段 2");
        phaser.arriveAndAwaitAdvance(); // 阶段 2 完成
    }).start();
}
phaser.arriveAndAwaitAdvance(); // 主线程等待阶段 1 完成
System.out.println("所有线程完成阶段 1");
phaser.arriveAndAwaitAdvance(); // 主线程等待阶段 2 完成
System.out.println("所有线程完成阶段 2");
  • Semaphore
    • 控制同时访问特定资源的线程数量。
    • 示例:限制对某个资源(如数据库连接)的访问。
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 10; i++) {
    new Thread(() -> {
        try {
            semaphore.acquire();
            // 访问资源
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            semaphore.release();
        }
    }).start();
}
  • Exchanger
    • 两个线程可以交换数据的同步点。
    • 示例:生产者和消费者线程交换数据。
Exchanger<String> exchanger = new Exchanger<>();
new Thread(() -> {
    try {
        String data = "Data from Thread 1";
        String received = exchanger.exchange(data);
        System.out.println("Thread 1 received: " + received);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}).start();
new Thread(() -> {
    try {
        String data = "Data from Thread 2";
        String received = exchanger.exchange(data);
        System.out.println("Thread 2 received: " + received);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}).start();

3. 锁和同步

  • ReentrantLock
    • 可重入锁,与 synchronized 关键字类似,但提供了更灵活的锁定操作。
    • 支持公平锁和非公平锁。
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
    // 访问共享资源
} finally {
    lock.unlock();
}
  • ReentrantReadWriteLock
    • 读写锁,允许多个读线程同时访问,但写线程独占访问。
    • 适用于读多写少的场景。
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
rwLock.readLock().lock();
try {
    // 读操作
} finally {
    rwLock.readLock().unlock();
}
rwLock.writeLock().lock();
try {
    // 写操作
} finally {
    rwLock.writeLock().unlock();
}
  • StampedLock
    • 提供了更高效的读写锁,支持乐观读。
    • 适用于大量读操作且较少写操作的场景。
StampedLock stampedLock = new StampedLock();
long stamp = stampedLock.readLock();
try {
    // 读操作
} finally {
    stampedLock.unlockRead(stamp);
}
stamp = stampedLock.writeLock();
try {
    // 写操作
} finally {
    stampedLock.unlockWrite(stamp);
}

4. 并发集合

  • ConcurrentHashMap
    • 高效的线程安全的哈希表。
    • 允许多个线程并发读写,适用于高并发场景。
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("key1", 1);
Integer value = map.get("key1");
  • ConcurrentSkipListMap
    • 线程安全的有序映射,内部使用跳表实现,适用于需要排序的高并发场景。
ConcurrentSkipListMap<String, Integer> map = new ConcurrentSkipListMap<>();
map.put("key1", 1);
Integer value = map.get("key1");
  • ConcurrentLinkedQueue
    • 非阻塞的线程安全队列,适用于高并发场景。
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
queue.offer("element");
String element = queue.poll();
  • ConcurrentLinkedDeque
    • 线程安全的双端队列,适用于高并发场景,可以从两端进行插入和移除操作。
ConcurrentLinkedDeque<String> deque = new ConcurrentLinkedDeque<>();
deque.offerFirst("element");
String element = deque.pollLast();
  • BlockingQueue 接口的实现类
    • ArrayBlockingQueue:基于数组的有界阻塞队列。
    • LinkedBlockingQueue:基于链表的可选有界阻塞队列。
    • PriorityBlockingQueue:支持优先级排序的无界阻塞队列。
    • DelayQueue:支持延时获取元素的无界阻塞队列。
    • SynchronousQueue:不存储元素的阻塞队列,每个插入操作必须等待另一个线程的移除操作。
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
queue.put("element");
String element = queue.take();
  • CopyOnWriteArrayList
    • 适用于读多写少的场景,读操作不需要加锁,写操作会创建副本。
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("element");
String element = list.get(0);
  • ConcurrentSkipListSet
    • 线程安全的有序集合,内部基于 ConcurrentSkipListMap 实现,适用于需要排序的高并发场景。
ConcurrentSkipListSet<String> set = new ConcurrentSkipListSet<>();
set.add("element");
boolean contains = set.contains("element");
  • CopyOnWriteArraySet
    • 适用于读多写少的场景,内部使用 CopyOnWriteArrayList 实现,读操作不需要加锁,写操作会创建副本。
CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
set.add("element");
boolean contains = set.contains("element");

5. 原子变量

java.util.concurrent.atomic 包提供了几种常见的原子变量类,原子变量类通过使用底层的 CAS(Compare-And-Swap)操作,提供了高效的线程安全操作,避免了传统锁机制带来的性能开销。

  • AtomicInteger
    • 提供了线程安全的整数操作。
AtomicInteger atomicInteger = new AtomicInteger(0);
atomicInteger.incrementAndGet();
int value = atomicInteger.get();
  • AtomicLong
    • 提供了线程安全的长整数操作。
AtomicLong atomicLong = new AtomicLong(0L);
atomicLong.incrementAndGet();
long value = atomicLong.get();
  • AtomicBoolean
    • 提供了线程安全的布尔值操作。
AtomicBoolean atomicBoolean = new AtomicBoolean(false);
atomicBoolean.set(true);
boolean value = atomicBoolean.get();
  • AtomicIntegerArray
    • 提供了线程安全的整数数组操作。
AtomicIntegerArray atomicArray = new AtomicIntegerArray(10);
atomicArray.set(0, 1);
int value = atomicArray.get(0);
  • AtomicLongArray
    • 提供了线程安全的长整数数组操作。
AtomicLongArray atomicLongArray = new AtomicLongArray(10);
atomicLongArray.set(0, 1L);
long value = atomicLongArray.get(0);
  • AtomicReferenceArray
    • 提供了线程安全的引用类型数组操作。
AtomicReferenceArray<String> atomicReferenceArray = new AtomicReferenceArray<>(10);
atomicReferenceArray.set(0, "initial");
String value = atomicReferenceArray.get(0);
  • AtomicStampedReference
    • 提供了带有版本号的引用类型操作,解决了 CAS 操作中的 ABA 问题。
AtomicStampedReference<String> atomicStampedReference = new AtomicStampedReference<>("initial", 0);
int[] stampHolder = new int[1];
String value = atomicStampedReference.get(stampHolder);
atomicStampedReference.compareAndSet("initial", "updated", stampHolder[0], stampHolder[0] + 1);
  • AtomicMarkableReference
    • 提供了带有标记位的引用类型操作。
AtomicMarkableReference<String> atomicMarkableReference = new AtomicMarkableReference<>("initial", false);
boolean[] markHolder = new boolean[1];
String value = atomicMarkableReference.get(markHolder);
atomicMarkableReference.compareAndSet("initial", "updated", false, true);
  • AtomicReference
    • 提供了线程安全的引用操作。
AtomicReference<String> atomicReference = new AtomicReference<>("initial");
atomicReference.set("updated");
String value = atomicReference.get();

JUC 包通过这些类和工具,为开发者提供了强大的并发编程能力。使用这些工具,可以更高效地管理线程、安全地共享数据和构建高性能的并发应用程序。

  • 10
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值