Java 并发编程(七)|JUC 工具类与线程安全集合考点

发布时间:2026/7/14 19:57:57

Java 并发编程(七)|JUC 工具类与线程安全集合考点
并发前言JUC工具类Callable 接口示例小结ReentrantLock 可重入锁使用优势劣势信号量 Semaphore示例CountDownLatch示例线程安全的集合类多环境使用ArrayList多线程环境使用队列多线程环境使用哈希表HashtableConcurrentHashMap全文总结 系列文章导航前言上一篇我们讲解了各类锁策略、CAS 无锁编程、synchronized 底层锁升级优化。本篇聚焦并发工程实战内容完整梳理 JUC 包核心工具类与各类线程安全集合覆盖 Callable、ReentrantLock、Semaphore、CountDownLatch 以及 ConcurrentHashMap 等高频面试考点配套可运行案例补齐 Java 并发编程业务落地相关知识点。JUC工具类JUCjava.util.concurrent这里的内容主要是一些多线程相关的组件。Callable 接口Callable 接口带有泛型参数的接口有返回值一种创建线程的方式。和 Runnable 对比1Runnable.run()无返回值2Callable.call()支持返回执行结果可抛出异常。注意Callable 不能直接传入 Thread 构造方法必须依靠FutureTask包装。示例实现使用Callable来创建线程计算123…1000。importjava.util.concurrent.Callable;importjava.util.concurrent.ExecutionException;importjava.util.concurrent.FutureTask;publicclassMain{publicstaticvoidmain(String[]args)throwsExecutionException,InterruptedException{//定义任务CallableIntegercallablenewCallableInteger(){OverridepublicIntegercall()throwsException{intsum0;for(inti1;i1000;i){sumi;}returnsum;}};//把任务放到线程中执行//callable不能直接传给Thread的构造方法要借用中间的类包装一下//futureTask相当于号码牌拿着号码牌取结果FutureTaskIntegerfutureTasknewFutureTask(callable);ThreadtnewThread(futureTask);t.start();//此处的get就能获取到callable里面返回的结果//线程是并发执行执行到主线程的get时t线程可能还没执行完此时get就会阻塞System.out.println(futureTask.get());}}小结线程的创建方式继承Thread类重写run方法可以创建单独的类也可以使用匿名内部类。实现Runnable接口重写run方法可以创建单独的类也可以使用匿名内部类。实现Callable接口重写call方法可以创建单独的类也可以使用匿名内部类。使用lambda表达式。ThreadFactory线程工厂。线程池。ReentrantLock 可重入锁使用ReentrantLocklocknewReentrantLock();lock.lock();//加锁try{//working}finally{lock.unlock();//一定不能忘记unlock的调用}相对来说synchronized是Java的内置锁由JVM自动管理锁的获取与释放无需手动调用解锁方法因此不会出现因忘记解锁或异常导致锁无法释放的问题。优势ReentrantLock 在加锁时有两种方式lock与synchronized类似若遇到锁冲突就会一直阻塞等待trylock尝试加锁若没加上就放弃给了更多的可操作空间。ReentrantLock 提供了公平锁的实现默认情况下是非公平锁。ReentrantLock 提供了更强大的等待通知机制。搭配Condition类实现等待通知可显示唤醒几个线程。劣势ReentrantLock 使用起来复杂容易忘记解锁。加锁时首选synchronized背后还有一系列的优化手段。信号量 Semaphore信号量就是一个计数器描述了“可用资源”的个数。信号量用法每次申请一个可用资源计数器-1 ⇒ P操作原子操作acquire。每次释放一个可用资源计数器1 ⇒ V操作原子操作release。假设信号量初始值为10已经进行了十次P操作之后值为零此时继续进行P操作会阻塞等待。锁本质上就是一种特殊的信号量即可用资源为1的信号量值只可能为1和0也就是二元信号量。操作系统提供了信号量实现提供了APIJVM封装了这样的API就可以在Java代码中使用。示例publicclassMain{publicstaticvoidmain(String[]args)throwsInterruptedException{SemaphoresemaphorenewSemaphore(4);semaphore.acquire();System.out.println(P 操作);semaphore.acquire();System.out.println(P 操作);semaphore.acquire();System.out.println(P 操作);semaphore.acquire();System.out.println(P 操作);semaphore.acquire();System.out.println(P 操作);//semaphore.release();}}开发中如果遇到了需要申请资源的场景就可以使用信号量来实现了。CountDownLatchCountDownLatch适用于多个线程来完成一系列任务的时候用来衡量任务的进度是否完成。CountDownLatch 的方法await调用时会阻塞就会等待其他线程完成任务所有的线程都完成了任务之后此时await才会返回就会继续往下走。countDown告诉countDownLatch当前这一个子任务完成了。如果 countDown 调用总次数小于初始化数值await 会永久阻塞。示例publicclassMain{publicstaticvoidmain(String[]args)throwsInterruptedException{//十个选手参赛await会在10次调用完countDown之后才能继续执行CountDownLatchcountDownLatchnewCountDownLatch(10);//如果循环次数少于10await会一直处于阻塞状态for(inti0;i10;i){intidi;ThreadtnewThread(()-{System.out.println(thread id);try{Thread.sleep(500);}catch(InterruptedExceptione){thrownewRuntimeException(e);}//通知当前任务已经执行完毕countDownLatch.countDown();});t.start();}countDownLatch.await();System.out.println(所有任务都完成了);}}线程安全的集合类数据结构中大部分的集合类都是线程不安全的早期VectorStackHashTable线程安全自带synchronized。那么如何保证线程安全呢1.加锁。2.标准库也提供了一些搭配的组件保证线程安全。多环境使用ArrayList使用同步机制synchronized或ReentrantLock。Collections.synchronizedListnew ArrayList会返回一个新的对象这个新的对象相当于给ArrayList套了一层壳这层壳就是在方法上直接使用synchronized。使用CopyOnWriteArrayList写时拷贝1比如两个线程使用同一个ArrayList可能会读可能会写两个线程读就直接读取若某个线程需要进行修改就把ArrayList复制出来一个副本该线程的修改操作就是在修改这个副本与此同时另一个线程仍然可以读取数据是在原来的数据上读取一旦这边修改完毕就会使用修改好的副本替代掉原来的数据往往就是一个引用赋值。2当前操作的ArrayList不能太大拷贝成本太高。3更适合于一个线程修改多个线程读取的情况。4适合于服务器的配置更新可以通过配置文件来描述配置的详细内容配置的内容会被读到内存中再由其他的线程读取这里的内容但是修改这个配置内容往往只有一个线程来修改。⇒ 使用某个命令让服务器重新加载配置就可以使用写时拷贝的方式了。多线程环境使用队列ArrayBlockingQueue基于数组实现的阻塞队列。LinkedBlockingQueue基于链表实现的阻塞队列。PriorityBlockingQueue基于堆实现的带优先级的阻塞队列。TransferQueue最多只包含一个元素的阻塞队列。多线程环境使用哈希表HashMap本身不是线程安全的HashtableHashtable 保证线程安全主要就是给关键方法加上synchronized直接加到方法上相当于给this加锁。只要两个线程在操作同一个Hashtable就会出现锁冲突。1.在不考虑触发扩容的前提下操作不同的链表是线程安全的比如A和C。2.相比之下若两个线程操作的是同一个链表才容易出现问题比如A和B。3.若两个线程操作的不是同一个链表就不用加锁否则需要加锁。ConcurrentHashMapConcurrentHashMap 最核心的改进把一个全局的大锁改进成了每个链表独立的一把小锁(把每个链表的头结点作为锁对象synchronized可以使用任意对象作为锁对象)大幅度降低了锁冲突概率。一个哈希表有很多这样的链表两个线程恰好同时访问同一个链表的情况较少。ConcurrentHashMap 充分利用了CAS特性把一些不必要加锁的环节省略加锁了。比如使用变量记录hash表中的元素个数就可以使用原子操作(CAS)修改元素个数ConcurrentHashMap针对读操作没有加锁。ConcurrentHashMap 在底层编码过程在中处理了一些细节修改时会避免使用、–这种非原子的操作而是使用进行修改本身就是原子的因此读的时候要么读到写之前的旧值要么读到写之后的新值不会出现读到一个修改到一半的值。写和写之间还是要加锁的。ConcurrentHashMap针对扩容操作做出了单独的优化。本身HashMap和Hashtable在扩容时都需要把所有的元素都拷贝一遍若元素很多拷贝就比较耗时。化整为零一旦需要扩容确实需要搬运但不是在一次操作中搬运完成而是分成多次来搬运每次只搬运一部分数据避免单次操作过于卡顿。在Java8之前ConcurrentHashMap 是基于分段锁(多个链表共用一把锁)的方式实现的Java8之后就是直接在链表头结点加锁的形式。全文总结CallableFutureTask 实现带返回值线程ReentrantLock、Semaphore、CountDownLatch 开发场景与底层特性各类线程安全 List、阻塞队列、哈希表对比重点掌握 ConcurrentHashMap JDK8 优化细节。至此 Java 并发编程系列全部知识点讲解完毕整套专栏从基础线程、同步机制、锁、CAS、JUC 工具到并发容器完整闭环全部代码均可直接运行。欢迎点赞收藏整套专栏评论区交流面试问题 系列文章导航本篇是「Java并发编程系列」的连载内容点击链接查看完整系列 上一篇Java 并发编程六并发进阶高频CAS、锁升级 下一篇Java IOFile 文件操作 字节流 / 字符流完整笔记 递归删除文件实战 点击直达「Java并发编程」专栏合集

相关新闻

境外新零售模式商城系统开发

境外新零售模式商城系统开发

2026/7/14 19:57:57

境外新零售模式商城系统开发要点编辑:araolin(私域邦网络土土哥)技术架构选择采用微服务架构确保系统可扩展性,支持高并发场景。推荐使用Spring Cloud或Kubernetes进行服务治理,数据库可选用MongoDB或Cassandra以适应非…

A3910与PIC18F45K22电机控制方案详解

A3910与PIC18F45K22电机控制方案详解

2026/7/14 19:57:57

1. 认识A3910与PIC18F45K22这对黄金搭档第一次看到A3910和PIC18F45K22这两个型号时,我正为一个工业控制项目发愁。客户需要一款能够精确控制直流电机,同时具备丰富外设接口的解决方案。经过反复对比,最终选择了这对组合——A3910作为电机驱动…

Vibe Coding实战:5个真实场景教你用自然语言构建完整应用

Vibe Coding实战:5个真实场景教你用自然语言构建完整应用

2026/7/14 19:47:57

理论说了很多,但Vibe Coding到底怎么用?今天我用5个真实场景,完整展示从需求描述到应用生成的全过程。每个场景我都会给出具体的prompt和关键迭代技巧,你可以直接复制到MonkeyCode里实践。## 场景一:个人作品集网站需求…

鱼池发黑发臭就是硝化系统崩了?9成人第一步就判断错了

鱼池发黑发臭就是硝化系统崩了?9成人第一步就判断错了

2026/7/14 21:28:01

很多鱼友一看到自家鱼池的水变得发黑发臭,第一反应就是“完了,硝化系统崩溃了”,然后赶紧换水、下药、加硝化菌,折腾一圈下来,水质反而更糟了。事实上,根据南京比德园艺服务有限公司过去十余年服务超500个项…

97.6%的ChatGPT使用者忽略的关键前提:你是否具备这3项底层能力?缺失1项即效率归零

97.6%的ChatGPT使用者忽略的关键前提:你是否具备这3项底层能力?缺失1项即效率归零

2026/7/14 21:28:01

更多请点击: https://codechina.net 第一章:ChatGPT 适合什么人用 ChatGPT 并非仅面向程序员或技术专家的专属工具,其核心价值在于降低信息获取、内容生成与逻辑表达的门槛。只要具备基础数字素养并有明确目标场景,不同背景的用户…

拼多多.NET接口对接全套工具:签名调试、SDK源码与API测试示例

拼多多.NET接口对接全套工具:签名调试、SDK源码与API测试示例

2026/7/14 21:28:01

本文还有配套的精品资源,点击获取 简介:专为.NET开发者准备的拼多多开放平台接入工具包,内置PddOpenSdk核心库,兼容.NET Core和.NET Framework,提供Mvc和Console两种典型应用场景示例。包含独立运行的API测试工程&a…

个人微信接口如何解决私域运营痛点

个人微信接口如何解决私域运营痛点

2026/7/14 21:28:01

如果你经常找代购、在小区团购群里买菜、或者关注过一些小商家的福利群,你一定遇到过这些场景: 在群里发一句“查快递”,机器人秒回单号;发一个链接,它自动帮你查优惠券;甚至你刚加上对方好友,…

精通前端WebAssembly性能加速与跨平台开发技术

精通前端WebAssembly性能加速与跨平台开发技术

2026/7/14 21:28:01

精通前端WebAssembly性能加速与跨平台开发技术 在当今高速发展的互联网时代,前端开发正面临着前所未有的性能挑战与跨平台需求。随着应用复杂度的不断提升,传统的JavaScript解决方案在某些高性能计算场景中逐渐显露出局限性。正是在这样的背景下&#xf…

计算机组成原理-实验三:从零搭建6116 SRAM读写时序与电路分析

计算机组成原理-实验三:从零搭建6116 SRAM读写时序与电路分析

2026/7/14 21:18:01

1. 6116 SRAM芯片基础认知第一次拿到6116这颗芯片时,我盯着24个引脚发了半天呆。作为经典的2K8位静态随机存储器,它就像个微型仓库——能存放2048个8位二进制数。与动态DRAM不同,SRAM不需要刷新电路,这让硬件设计简单不少&#xf…

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

2026/7/14 10:03:09

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator XUnity.AutoTranslator作为Unity游戏社区中最成熟的文本翻译解决方…

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

2026/7/13 20:43:19

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持 【免费下载链接】raspberrypi-kernel It provides openEuler kernel source for Raspberry Pi 项目地址: https://gitcode.com/openeuler/raspberrypi-kernel 前往项目官网免费下载&…

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

2026/7/13 20:43:10

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧 【免费下载链接】integration-test The repo contains test suits for system integration test 项目地址: https://gitcode.com/openeuler/integration-test 前往项目官网免费下载:…

XUnity.AutoTranslator 游戏实时翻译插件:从原理到实战的完整指南

XUnity.AutoTranslator 游戏实时翻译插件:从原理到实战的完整指南

2026/7/14 0:06:37

1. 项目概述:当游戏语言成为一堵墙作为一名玩了十几年日系、欧美独立游戏的“老油条”,我太懂那种面对一款心仪已久、画风玩法都戳中G点的游戏,却因为语言不通而望而却步的痛了。尤其是那些基于Unity引擎开发的、体量不大但内容精良的作品&am…

2026普通文员学数据分析的价值

2026普通文员学数据分析的价值

2026/7/14 0:06:37

一、2026年普通文员学习数据分析的必要性随着数字化转型加速,数据分析技能正逐渐成为职场基础能力。普通文员学习数据分析可以提升工作效率、增强竞争力,并为职业转型提供更多可能性。二、数据分析对文员的价值自动化办公:通过数据分析工具&a…

2026从计划员到主管,生产管理者学数据分析有用吗?

2026从计划员到主管,生产管理者学数据分析有用吗?

2026/7/14 0:06:37

一、生产管理领域的职业发展路径 从计划员到主管的角色转变,是生产管理者职业发展的典型路径。计划员主要负责生产排程、库存管理和资源协调等基础工作,而主管则需要承担团队管理、决策支持和效率优化等更高级别的职责。这种转变不仅仅是职位的提升&…