当前位置: 首页 > news >正文

JUC中的所有类详解

JUC中的所有类详解

    • 一、基础概念
      • 1. JUC简介
      • 2. JUC基本组成
    • 二、常用组件详解
      • 1. 线程池(Executor、ExecutorService、ScheduledExecutorService)
        • 1.1 线程池的概念与作用
        • 1.2 如何使用线程池
        • 1.3 ScheduledExecutorService的使用方法
      • 2. 同步工具
        • 2.1 ReentrantLock
        • 2.2 Semaphore
        • 2.3 CountDownLatch
        • 2.4 CyclicBarrier
        • 2.5 Phaser
      • 3. 原子类
        • 3.1 AtomicInteger
        • 3.2 AtomicReference
      • 4. 并发集合
        • 4.1 ConcurrentHashMap
        • 4.2 CopyOnWriteArrayList
    • 三、常见实践
      • 1. 使用线程池
      • 2. 使用锁机制
      • 3. 使用Fork/Join框架进行数据处理
    • 四、最佳实践
      • 1. 选择合适的并发工具
      • 2. 减少锁争用
      • 3. 避免死锁
    • 五、底层原理
      • 1. 线程池底层原理
      • 2. 原子类底层实现
      • 3. 并发集合底层实现
      • 4. 同步工具底层实现
    • 六、总结
    • 七、参考资料

一、基础概念

1. JUC简介

Java Util Concurrent(JUC)是Java并发编程的核心库,它提供了丰富的工具和类来帮助开发者更高效地处理多线程问题。JUC的目标是简化并发编程的复杂性,提供经过验证的并发工具,让开发者能够专注于业务逻辑,而不是底层的线程同步和资源管理。

2. JUC基本组成

JUC主要由以下几个部分组成:

  1. 同步辅助类:如ReentrantLockSemaphoreCountDownLatch等,用于解决线程同步和协调问题。
  2. 并发集合:如ConcurrentHashMapCopyOnWriteArrayList等,提供了线程安全的集合操作。
  3. 执行器框架:如ExecutorServiceScheduledExecutorService等,用于管理和调度线程池。
  4. 原子变量:如AtomicIntegerAtomicReference等,提供了线程安全的变量操作。

二、常用组件详解

1. 线程池(Executor、ExecutorService、ScheduledExecutorService)

1.1 线程池的概念与作用

线程池是一种用于管理和复用线程的机制,它可以有效降低线程创建和销毁的开销,提高程序的性能和资源利用率。

1.2 如何使用线程池
// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(4);

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

// 关闭线程池
executor.shutdown();
1.3 ScheduledExecutorService的使用方法
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);

// 定时任务:每2秒执行一次
scheduler.scheduleAtFixedRate(() -> {
    System.out.println("定时任务执行中...");
}, 0, 2, TimeUnit.SECONDS);

2. 同步工具

2.1 ReentrantLock

适用场景:解决多线程竞争资源的问题,如多线程同时对同一个数据进行写操作。

代码使用案例:通过生产者消费者模式演示ReentrantLock的使用。

public class ProducerConsumer {
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    private final List<Integer> list = new ArrayList<>();
    private final int capacity = 10;

    public void produce(int value) {
        lock.lock();
        try {
            while (list.size() == capacity) {
                notFull.await();
            }
            list.add(value);
            notEmpty.signal();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }

    public Integer consume() {
        lock.lock();
        try {
            while (list.isEmpty()) {
                notEmpty.await();
            }
            Integer value = list.remove(0);
            notFull.signal();
            return value;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }
}

源码分析:ReentrantLock基于AQS(AbstractQueuedSynchronizer)的实现原理,通过FIFO队列管理线程的获取和释放。

2.2 Semaphore

适用场景:实现服务接口限流、数据库连接池等。

代码使用案例:使用Semaphore限制并发访问的线程数。

public class SemaphoreExample {
    private final Semaphore semaphore = new Semaphore(3); // 最大允许3个线程同时访问

    public void accessResource() {
        try {
            semaphore.acquire();
            System.out.println("资源被访问,当前线程:" + Thread.currentThread().getName());
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            semaphore.release();
        }
    }
}

源码分析:Semaphore同样基于AQS实现,通过计数器管理资源的可用性。

2.3 CountDownLatch

适用场景:模拟百米赛跑、多任务完成后合并汇总。

代码使用案例:通过CountDownLatch实现多线程任务的同步。

public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3);

        // 启动3个线程
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                System.out.println("线程:" + Thread.currentThread().getName() + " 执行完成");
                latch.countDown();
            }).start();
        }

        // 主线程等待所有子线程完成
        latch.await();
        System.out.println("所有线程执行完成");
    }
}

源码分析:CountDownLatch内部维护一个计数器,通过countDown()减少计数,await()阻塞等待计数归零。

2.4 CyclicBarrier

适用场景:模拟人满发车、多线程批量处理数据。

代码使用案例:使用CyclicBarrier实现多线程任务的分阶段执行。

public class CyclicBarrierExample {
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(3, () -> {
            System.out.println("所有线程完成一个阶段,开始下一个阶段");
        });

        // 启动3个线程
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                try {
                    System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行");
                    Thread.sleep(1000);
                    barrier.await();
                    System.out.println("线程:" + Thread.currentThread().getName() + " 完成一个阶段");
                } catch (InterruptedException | BrokenBarrierException e) {
                    Thread.currentThread().interrupt();
                }
            }).start();
        }
    }
}

源码分析:CyclicBarrier通过循环屏障机制实现多线程的分阶段同步。

2.5 Phaser

适用场景:多线程批量处理数据、阶段性任务。

代码使用案例:使用Phaser实现多阶段任务的同步。

public class PhaserExample {
    public static void main(String[] args) {
        Phaser phaser = new Phaser(3);

        // 启动3个线程
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                try {
                    System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行阶段1");
                    Thread.sleep(1000);
                    phaser.arriveAndAwaitAdvance(); // 完成阶段1,等待其他线程

                    System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行阶段2");
                    Thread.sleep(1000);
                    phaser.arriveAndAwaitAdvance(); // 完成阶段2,等待其他线程
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }).start();
        }

        phaser.arriveAndDeregister(); // 主线程完成注册
    }
}

源码分析:Phaser通过阶段计数器管理多线程的同步,支持动态注册和注销。

3. 原子类

3.1 AtomicInteger

适用场景:实现线程安全的计数器。

代码使用案例:使用AtomicInteger进行线程安全的计数。

public class AtomicIntegerExample {
    private AtomicInteger count = new AtomicInteger(0);

    public void increment() {
        count.getAndIncrement();
    }

    public int getCount() {
        return count.get();
    }
}

源码分析:AtomicInteger基于CAS(Compare-And-Swap)操作实现线程安全的原子操作。

3.2 AtomicReference

适用场景:实现线程安全的对象引用。

代码使用案例:使用AtomicReference进行线程安全的对象操作。

public class AtomicReferenceExample {
    private AtomicReference<String> reference = new AtomicReference<>("初始值");

    public void updateValue(String newValue) {
        reference.set(newValue);
    }

    public String getValue() {
        return reference.get();
    }
}

源码分析:AtomicReference通过CAS操作实现线程安全的对象引用更新。

4. 并发集合

4.1 ConcurrentHashMap

适用场景:高并发场景下的键值存储。

代码使用案例:使用ConcurrentHashMap进行线程安全的Map操作。

public class ConcurrentHashMapExample {
    private ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();

    public void put(String key, String value) {
        map.put(key, value);
    }

    public String get(String key) {
        return map.get(key);
    }
}

源码分析:ConcurrentHashMap通过分段锁和哈希表扩展实现高并发的键值存储。

4.2 CopyOnWriteArrayList

适用场景:遍历操作远多于修改操作的场景。

代码使用案例:使用CopyOnWriteArrayList进行线程安全的List操作。

public class CopyOnWriteArrayListExample {
    private CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();

    public void add(String value) {
        list.add(value);
    }

    public List<String> getAll() {
        return list;
    }
}

源码分析:CopyOnWriteArrayList通过写时复制机制实现线程安全的List操作。

三、常见实践

1. 使用线程池

通过实际案例演示如何使用线程池来提高程序的性能和资源利用率。

public class ThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(4);

        // 提交10个任务
        for (int i = 0; i < 10; i++) {
            executor.submit(() -> {
                System.out.println("任务执行中,线程:" + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }

        executor.shutdown();
    }
}

2. 使用锁机制

介绍如何使用ReentrantLock等锁机制来解决线程安全问题,并提供实际代码示例。

public class LockExample {
    private final ReentrantLock lock = new ReentrantLock();
    private int count = 0;

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        return count;
    }
}

3. 使用Fork/Join框架进行数据处理

讲解Fork/Join框架的原理和使用方法,并通过案例展示其在大数据处理中的优势。

public class ForkJoinExample extends RecursiveTask<Integer> {
    private final int threshold = 2;
    private int start;
    private int end;

    public ForkJoinExample(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        if (end - start <= threshold) {
            int sum = 0;
            for (int i = start; i < end; i++) {
                sum += i;
            }
            return sum;
        } else {
            int mid = (start + end) / 2;
            ForkJoinExample left = new ForkJoinExample(start, mid);
            ForkJoinExample right = new ForkJoinExample(mid, end);
            left.fork();
            right.fork();
            return left.join() + right.join();
        }
    }

    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool();
        ForkJoinExample task = new ForkJoinExample(0, 100);
        System.out.println(pool.invoke(task));
    }
}

四、最佳实践

1. 选择合适的并发工具

根据不同的并发场景,分析如何选择最合适的并发工具来解决问题。

  • 高并发读操作:使用ConcurrentHashMap
  • 高并发写操作:使用CopyOnWriteArrayList
  • 定时任务:使用ScheduledExecutorService
  • 线程安全计数:使用AtomicInteger

2. 减少锁争用

提供一些减少锁争用的技巧和策略,提高程序的并发性能。

  • 使用细粒度锁:如ReentrantLock的分段锁。
  • 使用无锁数据结构:如AtomicInteger
  • 避免死循环中的锁操作:将锁操作放在循环外部。

3. 避免死锁

分析死锁产生的原因,并介绍如何通过设计和编码避免死锁的发生。

  • 按顺序获取锁:确保所有线程按相同的顺序获取多个锁。
  • 使用tryLock:尝试获取锁,避免无限期等待。
  • 减少锁的持有时间:尽量缩短锁的持有时间。

五、底层原理

1. 线程池底层原理

深入分析线程池的底层实现,包括工作线程的创建、任务队列的管理以及拒绝策略的执行。

  • 工作线程:线程池中的线程负责执行任务。
  • 任务队列:存储待执行的任务。
  • 拒绝策略:当任务队列满且线程池已满时,执行拒绝策略。

2. 原子类底层实现

讲解原子类的底层实现原理,如CAS操作等,帮助理解原子类的高效性和线程安全性。

  • CAS操作:Compare-And-Swap,原子比较并交换。
  • Unsafe类:底层操作内存地址的类。

3. 并发集合底层实现

详细分析并发集合的底层数据结构和算法,如ConcurrentHashMap的分段锁和哈希表扩展等。

  • 分段锁:将哈希表分为多个段,每个段独立加锁。
  • 哈希表扩展:动态扩展哈希表以适应更多数据。

4. 同步工具底层实现

讲解ReentrantLock、Semaphore等同步工具的底层实现原理,包括AQS(AbstractQueuedSynchronizer)的使用。

  • AQS:AbstractQueuedSynchronizer,用于构建锁和同步器的框架。
  • FIFO队列:管理线程的获取和释放顺序。

六、总结

JUC中的类为Java并发编程提供了强大的工具,通过合理选择和使用这些工具,可以有效解决多线程编程中的复杂问题。以下是一些关键点总结:

  • 线程池:有效管理线程资源,提高性能。
  • 同步工具:解决线程同步和协调问题。
  • 原子类:提供高效的线程安全操作。
  • 并发集合:支持高并发场景下的数据存储和操作。

七、参考资料

  • JUC官方文档

如果你觉得这篇文章对你有帮助,不妨点赞、关注和收藏!你的支持是我继续创作的动力,也让我有更多机会分享更多优质内容。谢谢大家!

相关文章:

  • 架构设计基础:面向对象设计的原则
  • 【FPGA实战】基于DE2-115实现数字秒表
  • 【C++】自实现简谱播放
  • ESP-IDF中调用xEventGroupWaitBits函数失效问题的分析(1)
  • 碰一碰发视频网页版本开发的源码搭建指南
  • 三、FFmpeg学习笔记
  • 26--DHCP Snooping:网络世界的“房产中介资格认证系统“
  • 解锁健康密码,踏上养生旅程
  • YOLOV8 训练姿态检测模型
  • linux权限
  • 【实战】渗透测试下的传输命令
  • Linux安装Ubuntu24.04系统 并安装配置Nvidia 4090 显卡驱动
  • PTS-G3K13M RF Generator 3kW / 13MHz User’s Manual 手侧
  • Redis 6.2.6 生产环境单机配置详解redis.conf
  • 循环神经网络 - 简单循环网络
  • 正则表达式最小生成树算法题
  • 安全编码课程 实验5 动态内存(3)
  • Linux进程间通信:无名管道与有名管道的原理与实践
  • 4月1日工作日志
  • 用python编写poc的流程
  • 流失海外79年,两卷战国帛书回归祖国
  • 湖南4个县市区被确定为野生蘑菇中毒高风险区:中毒尚无特效解毒药
  • 中国情怀:时代记录与家国镜相|澎湃·镜相第三届非虚构写作大赛征稿启事
  • 俄媒:俄乌伊斯坦布尔谈判将于北京时间今天17时30分开始
  • 国家卫健委通报:吊销肖某医师执业证书,撤销董某莹四项证书
  • 宜昌谱写新叙事:长江大保护与高质量发展如何相互成就