Java JUC概述

news/2024/11/24 7:44:44/

Java JUC(Java Util Concurrent)是 Java 平台提供的并发编程工具包,它提供了一系列的工具类和接口,用于简化多线程编程。JUC 中的类和接口都是基于 Java 平台的底层并发原语(如锁、信号量、原子变量等)实现的,可以帮助开发者更加方便和安全地完成多线程编程。

JUC 中的常用类和接口

1. Lock 和 ReentrantLock

Lock 接口是 Java 并发包中提供的一种比 synchronized 更加灵活的锁机制。它提供了更加细粒度的控制,可以实现更加复杂的线程同步操作。ReentrantLock 是 Lock 接口的一个实现类,它提供了与 synchronized 相同的互斥性和内存可见性,同时还提供了更多的高级功能,如可重入锁、公平锁等。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class LockDemo {private Lock lock = new ReentrantLock();public void print() {lock.lock();try {// 线程安全的代码System.out.println(Thread.currentThread().getName() + " is running");} finally {lock.unlock();}}
}

2. Condition

Condition 接口是 Lock 接口提供的一个高级功能,它可以用于实现线程之间的通信。一个 Condition 对象可以和一个 Lock 对象关联,当一个线程调用 Condition 的 await() 方法时,它会释放掉与这个 Condition 对象关联的 Lock 对象的锁,并进入等待状态;当另一个线程调用 Condition 的 signal() 或 signalAll() 方法时,它会通知一个或所有正在等待的线程恢复执行。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class ConditionDemo {private Lock lock = new ReentrantLock();private Condition condition = lock.newCondition();private int count = 0;public void produce() {lock.lock();try {while (count >= 10) {condition.await();}count++;System.out.println(Thread.currentThread().getName() + " produce, count = " + count);condition.signalAll();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public void consume() {lock.lock();try {while (count <= 0) {condition.await();}count--;System.out.println(Thread.currentThread().getName() + " consume, count = " + count);condition.signalAll();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}
}

3. Semaphore

Semaphore 是一种计数信号量,它可以用于控制同时访问某个资源的线程数量。Semaphore 维护了一个计数器,每当一个线程访问该资源时,计数器就会减一;当计数器为零时,所有试图访问该资源的线程都会被阻塞,直到计数器大于零。

import java.util.concurrent.Semaphore;public class SemaphoreDemo {private Semaphore semaphore = new Semaphore(5);public void access() {try {semaphore.acquire();// 线程安全的代码System.out.println(Thread.currentThread().getName() + " is running");} catch (InterruptedException e) {e.printStackTrace();} finally {semaphore.release();}}
}

4. CountDownLatch

CountDownLatch 是一种同步工具类,它可以让一个或多个线程等待其他线程完成操作后再继续执行。CountDownLatch 维护了一个计数器,线程调用它的 await() 方法会阻塞,直到计数器变为零;而其他线程完成操作后,可以调用 CountDownLatch 的 countDown() 方法将计数器减一。

import java.util.concurrent.CountDownLatch;public class CountDownLatchDemo {private CountDownLatch countDownLatch = new CountDownLatch(3);public void task() {try {// 模拟耗时操作Thread.sleep((long) (Math.random() * 1000));System.out.println(Thread.currentThread().getName() + " is running");} catch (InterruptedException e) {e.printStackTrace();} finally {countDownLatch.countDown();}}public void start() {for (int i = 0; i < 3; i++) {new Thread(this::task).start();}try {countDownLatch.await();System.out.println("All tasks have been completed");} catch (InterruptedException e) {e.printStackTrace();}}
}

5. CyclicBarrier

CyclicBarrier 是一种同步工具类,它可以让一组线程在达到某个共同点之前相互等待。CyclicBarrier 维护了一个计数器和一个栅栏点,每当一个线程到达栅栏点时,计数器就会减一;当计数器为零时,所有线程就可以继续执行。

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;public class CyclicBarrierDemo {private CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {System.out.println("All threads have arrived at the barrier");});public void task() {try {// 模拟耗时操作Thread.sleep((long) (Math.random() * 1000));System.out.println(Thread.currentThread().getName() + " has arrived at the barrier");cyclicBarrier.await();System.out.println(Thread.currentThread().getName() + " is running");} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}}public void start() {for (int i = 0; i < 3; i++) {new Thread(this::task).start();}}
}

JUC 中的常用工具类

1. Executors

Executors 是一个工具类,用于创建线程池。它提供了一些静态方法,可以方便地创建不同类型的线程池。常用的方法有:

  • newFixedThreadPool(int nThreads):创建一个固定大小的线程池,该线程池中的线程数始终为 nThreads。
  • newCachedThreadPool():创建一个缓存线程池,该线程池可以根据需要创建新的线程,但在有可用线程时重用旧线程。
  • newSingleThreadExecutor():创建一个单线程池,该线程池中始终只有一个线程在工作。
  • newScheduledThreadPool(int corePoolSize):创建一个定时任务线程池,该线程池可以在指定的延迟时间后执行任务,也可以按照固定的时间间隔执行任务。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ExecutorsDemo {private ExecutorService executorService = Executors.newFixedThreadPool(5);public void execute() {executorService.execute(() -> {// 线程安全的代码System.out.println(Thread.currentThread().getName() + " is running");});}public void shutdown() {executorService.shutdown();}
}

2. Future 和 FutureTask

Future 接口表示一个异步计算的结果,它提供了一些方法,可以查询计算是否完成、等待计算完成并获取结果。FutureTask 是 Future 接口的一个实现类,它可以用于异步执行任务,并且可以在任务执行完成后获取任务的执行结果。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class FutureTaskDemo {private FutureTask<Integer> futureTask = new FutureTask<>(() -> {// 模拟耗时操作Thread.sleep((long) (Math.random() * 1000));return 1;});public void start() {new Thread(futureTask).start();}public void get() {try {int result = futureTask.get();System.out.println("Result: " + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}
}

3. ConcurrentHashMap

ConcurrentHashMap 是一个线程安全的哈希表,它可以在高并发的情况下提供更好的性能。它的实现原理是将整个哈希表分成多个段,每个段都是一个独立的哈希表,可以独立地进行添加、删除、修改等操作。这样,当多个线程同时访问不同的段时,就可以实现真正的并行操作,从而提高了并发性能。

import java.util.concurrent.ConcurrentHashMap;public class ConcurrentHashMapDemo {private ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();public void put(String key, int value) {map.put(key, value);}public int get(String key) {return map.get(key);}
}

JUC 中的高级特性

1. AQS

AQS(AbstractQueuedSynchronizer)是 JUC 中的一个重要类,它提供了一种通用的同步框架,可以用于实现各种同步器,如锁、信号量、倒计时门栓等。AQS 的核心思想是基于一个先进先出(FIFO)的队列,来管理等待获取同步状态的线程。当一个线程获取同步状态失败时,它会被封装成一个节点,然后加入到等待队列中,等待其他线程释放同步状态后再次尝试获取。

2. ForkJoin

ForkJoin 框架是 JUC 中的一个高性能并行计算框架,它可以将一个大任务拆分成多个小任务,并行地执行这些小任务,最后将小任务的结果合并成大任务的结果。ForkJoin 框架的核心思想是“工作窃取”,即当一个线程的任务执行完毕后,它可以从其他线程的任务队列中窃取一个任务来执行,以此来实现负载均衡。

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;public class ForkJoinDemo extends RecursiveTask<Integer> {private int start;private int end;public ForkJoinDemo(int start, int end) {this.start = start;this.end = end;}@Overrideprotected Integer compute() {if (end - start <= 100) {int sum = 0;for (int i = start; i <= end; i++) {sum += i;}return sum;} else {int mid = (start + end) / 2;ForkJoinDemo left = new ForkJoinDemo(start, mid);ForkJoinDemo right = new ForkJoinDemo(mid + 1, end);left.fork();right.fork();return left.join() + right.join();}}public static void main(String[] args) {ForkJoinPool forkJoinPool = new ForkJoinPool();ForkJoinDemo task = new ForkJoinDemo(1, 1000);Integer result = forkJoinPool.invoke(task);System.out.println("Result: " + result);}
}

总结

Java JUC 提供了一系列的工具类和接口,用于简化多线程编程。在实际开发中,我们应该根据具体的业务需求选择合适的工具类和接口,以提高程序的并发性能和可靠性。同时,我们还应该遵守多线程编程的最佳实践,如避免死锁、竞态条件等问题,以确保程序的正确性和稳定性。

公众号请关注"果酱桑", 一起学习,一起进步!


http://www.ppmy.cn/news/483128.html

相关文章

【vue+el-transfer】穿梭框实现及遇到的bug,已解决

昨晚加班写的穿梭框组件&#xff0c;一边写一边遇到bug&#xff0c;果然只有bug才会让你印象更深刻&#xff0c;更值得记录 封装成组件FreezeTransfer 效果如下&#xff1a; 主要参考了官网上可搜索的这个示例 先说遇到的bug&#xff0c;然后贴完整的代码 1、el-transfer数据…

k8s 大量生成驱逐节点

K8s部署和被驱逐&#xff1a; 调度成功&#xff0c;进入pending状态然后进入容器创建podCreating状态发现资源不足&#xff08;不满足某个条件&#xff09;导致任务直接失败&#xff0c;被驱逐出这个节点重新进行调度&#xff0c;重复这个过程所有的节点都不满足这个条件&…

高防IP如何防止爬虫和Web攻击?

高防IP如何防止爬虫和Web攻击&#xff1f;随着互联网的发展&#xff0c;各种类型的网络攻击和爬虫行为也越来越多。为了保护网站的安全和稳定性&#xff0c;许多网站都采用了高防IP来防止爬虫和Web攻击。那么高防IP是如何防止爬虫和Web攻击的呢&#xff1f;下面我们来详细了解一…

Linux ~ NFS 文件共享

Ubuntu 下载nfs服务软件包 sudo apt-get install nfs-kernel-server配置nfs vim /etc/exports表头表头/mnt/*指示要共享的目录*代表允许所有的网络段访问rw指示具有可读写的权限sync指示资料同步写入内存和硬盘no_root_squash客户端分享目录使用者的权限 启动rpcbind服务 …

浅谈医院电气火灾的起因与预防

摘要:医院属公共场所&#xff0c;建筑密集&#xff0c;人员集中&#xff0c;且弱势群体&#xff08;病人&#xff09;居多&#xff0c;一旦发生火灾&#xff0c;可能造成重大财产损失和人员伤亡。在引起医院火灾的各种因素中&#xff0c;电气火灾由于医院建筑功能与其他建筑不同…

19.组件之间传递数据

不同组件传递数据的时候&#xff0c;最好不要直接传递复杂数据类型(比如对象&#xff0c;数组) 前端需要处理的数据层级一般不会很多&#xff0c;需要在多处使用的数据一般会被放到数据库中 目录 1 组件的关系 2 父向子传递数据-props 3 子向父传递数据-自定义事件 4 …

【面试题】2023-04,05面试集合,搞钱要紧 【抓紧面试】

大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 // 四月中旬公司裁员&#xff0c;我所在的项目组卡一下全部没了。来公司两年多&#xff0c;…

无线鼠标插上去没反应

1.检查是否打开蓝牙和设备连接成功&#xff1a; 2.排除上面问题就有可能硬件问题 我经常遇到就是电池接触不良&#xff0c;把电池拆下来&#xff0c;重新装就行了。&#xff08;有时候把鼠标和电脑放到书包&#xff0c;背回家就会&#xff09;