专栏:JavaEE初阶起飞计划

个人主页:手握风云

目录

一、JUC的常见类

1.1. Callable接口

1.2. ReentrantLock​

1.3. 信号量Semaphore

1.4. CountDownLatch

二、线程安全的集合类

2.1. 多线程环境使用 ArrayList​

2.2. 多线程环境使用哈希表


一、JUC的常见类

1.1. Callable接口

        Callable是一个interface,类似于Runnable,把线程封装了⼀个"返回值",方便程序员借助多线程的方式计算结果。

        下面一个场景:创建线程计算1+2+3+4+……+100。

        第一种写法:通过Runnable的方案,需要借助成员变量sum,耦合性比较高。

public class Demo1 {private static int sum = 0;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {int ret = 0;for (int i = 1; i <= 100; i++) {ret += i;}sum = ret;});t1.start();t1.join();System.out.println(sum);}
}

        第二种写法:使用Callable版本。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class Demo2 {public static void main(String[] args) throws ExecutionException, InterruptedException {Callable<Integer> callable = new Callable<>(){@Overridepublic Integer call() throws Exception {int ret = 0;for (int i = 1; i <= 100; i++) {ret += i;}return ret;}};FutureTask<Integer> task = new FutureTask<Integer>(callable);Thread t = new Thread(task);t.start();System.out.println(task.get());}
}

        Callable带有泛型参数,可以作为返回值计算结果。我们还需要重写里面的call()方法来计算结果,再把callable利用FutureTask包装一下,然后创建线程,将task传入线程的构造方法中。在主线程中调用task.get(),能够阻塞等待新线程计算完毕,并获取到FutureTask中的结果。

        对于FutureTask的理解,FutureTask是 Java 并发编程中异步任务与结果获取的桥梁,通过封装状态管理、线程同步和异常处理,显著简化了异步编程模型。我们可以想象去吃麻辣烫,当餐点好后,后厨就开始做了,同时前台会给你一张 "小票",这个小票就是FutureTask,后面我们可以随时凭这张小票去查看自己的这份麻辣烫做出来了没。

1.2. ReentrantLock​

        ReentrantLock也是可重入锁,"Reentrant" 这个单词的原意就是 "可重入"​。与synchronized定位类似,都是用来实现互斥效果,保证线程安全。

import java.util.concurrent.locks.ReentrantLock;public class Demo3 {private static int count = 0;public static void main(String[] args) throws InterruptedException {ReentrantLock locker = new ReentrantLock();Thread t1 = new Thread(() -> {for (int i = 0; i < 50_000; i++) {locker.lock();count++;locker.unlock();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50_000; i++) {locker.lock();count++;locker.unlock();}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}
}

        ReentrantLock和synchronized 的区别:

  • synchronized 是一个关键字,是 JVM 内部实现的。ReentrantLock是标准库的一个类, 在 JVM外实现的。
  • synchronized使用时不需要手动释放锁,ReentrantLock 使用时需要手动释放,使用起来更灵活,但是也容易遗漏unlock。
  • synchronized 在申请锁失败时,会死等,ReentrantLock可以通过trylock的方式等待一段时间就放弃。
  • synchronized是非公平锁,ReentrantLock默认是非公平锁。可以通过构造方法传入一个true 开启公平锁模式。
  • 更强大的唤醒机制,synchronized 是通过 Object 的 wait / notify 实现等待-唤醒. 每次唤醒的是一个随机等待的线程。ReentrantLock 搭配 Condition 类实现等待-唤醒, 可以更精确控制唤醒某个指定的线程。

1.3. 信号量Semaphore

        信号量,用来表示 "可用资源的个数",本质上就是一个计数器。我们申请资源(P操作),就会使计数器-1;释放资源(V操作),就会使计数器+1。上述+1、-1的操作都是原子的。如果计数器为0,再去申请资源,就会造成阻塞。举个例子,我们开车寻找停车场时,开进去,电子牌上的空闲车位就会-1,开出去,电子牌上的空闲车位就会+1。如果没有空闲车位,就得停车等待或者寻找其他停车场。

import java.util.concurrent.Semaphore;public class Demo3 {public static void main(String[] args) throws InterruptedException {// 初始许可数为3,也就是“可用资源”的个数Semaphore semaphore = new Semaphore(3);semaphore.acquire();System.out.println("执行P操作");semaphore.acquire();System.out.println("执行P操作");semaphore.acquire();System.out.println("执行P操作");semaphore.release();}
}

        上面初始值设为3,当我们申请4次之后,就会产生阻塞。

import java.util.concurrent.Semaphore;public class Demo3 {public static void main(String[] args) throws InterruptedException {// 初始许可数为3,也就是“可用资源”的个数Semaphore semaphore = new Semaphore(3);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();}
}

        信号量相当于锁概念的延伸。换句话说,锁也可以看作时初始值为1的特殊信号量。如果我们想要编写的多线程代码不允许使用锁,也可以使用信号量保证线程安全。

import java.util.concurrent.Semaphore;public class Demo4 {private static int count = 0;public static void main(String[] args) throws InterruptedException {Semaphore semaphore = new Semaphore(1);// 创建一个线程t1,该线程执行的任务是:循环50_000次,每次执行时获取semaphore的许可,然后count加1,最后释放semaphore的许可Thread t1 = new Thread(() ->{for (int i = 0; i < 50_000; i++) {try {//  获取semaphore的许可semaphore.acquire();// count加1count++;// 释放semaphore的许可semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}}});Thread t2 = new Thread(() ->{for (int i = 0; i < 50_000; i++) {try {semaphore.acquire();count++;semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}
}

1.4. CountDownLatch

        CountDownLatch是Java 并发包中的同步辅助工具,用于协调多个线程的执行顺序,同时等待多个任务执行结束。比如在跑步⽐赛中,8个选⼿依次就位,哨声响才同时出发;所有选⼿都通过终点,才能公布成绩。

import java.util.concurrent.CountDownLatch;public class Demo5 {public static void main(String[] args) throws InterruptedException {CountDownLatch latch = new CountDownLatch(8);for (int i = 0; i < 8; i++) {int id = i;Thread t = new Thread(() -> {// 通过sleep模拟try {Thread.sleep(1_000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程" + id + "执行完毕");// 计数器减一,相当于一个运动员到达终点latch.countDown();});t.start();}// 主线程通过await()方法等待所有线程结束latch.await();System.out.println("所有任务执行完毕");}
}

        CountDownLatch通常用于一些特场景:在开发工作中,把一个大任务拆分成多个子任务,通过多线程并发执行,把所有任务完成之后才能进入下一阶段。

二、线程安全的集合类

2.1. 多线程环境使用 ArrayList​

  • 自己使用同步机制 (synchronized 或者 ReentrantLock)​
  • Collections.synchronizedList(new ArrayList)。synchronizedList 是标准库提供的一个基于 synchronized 进行线程同步的 List. synchronizedList 的关键操作上都带有 synchronized​。

2.2. 多线程环境使用哈希表

        HashMap 本身不是线程安全的,在多线程环境下可以使用Hashtable​或者ConcurrentHashMap。而Hashtable类似于Vector,在方法名上加上synchronized修饰,所以不推荐使用。

import java.util.Hashtable;public class Demo6 {public static void main(String[] args) {Hashtable<String, String> hashtable = new Hashtable<>();hashtable.put("111","aaa");hashtable.get("111");}
}
public synchronized V put(K key, V value) {……
}public synchronized V get(Object key) {……
}

        ConcurrentHashMap最大的调整就是针对锁的粒度进行可优化。对于Hashtable来说,针对this加锁,任何线程,只要操作这个哈希表都可能触发锁竞争。

        两个线程针对同一变量进行修改才会引发线程安全,所以针对哈希表来说,如果两个线程的修改是在不同链表上,线程就是安全的。针对同一链表时,才引入阻塞。在ConcurrentHashMap中,每个链表都有一把锁,称为“锁桶”。由于是不同的锁对象,出发锁竞争的概率就会降低。

        在实际中,一个哈希表的桶的个数非常多,针对哈希表的操作,大部分是分布在不同桶上,触发锁竞争的概率可以忽略不计。

        ConcurrentHashMap扩容的时候,采取“化整为零”的方案。因为如果哈希表原来的元素很多,扩容会造成很大的开销。为了保证线程安全,必须得加锁,如果全部进行搬运,持有锁的时间比较长,其他线程就无法正常使用哈希表了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/917784.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/917784.shtml
英文地址,请注明出处:http://en.pswp.cn/news/917784.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是RabbitMQ?

什么是RabbitMQ? 一、什么是RabbitMQ? 二、Rabbitmq 的使用场景? 三、RabbitMQ基本概念 四、RabbitMQ的工作模式 1. **简单队列模式(Simple Queue)** 2. **工作队列模式(Work Queue)** 3. **发布/订阅模式(Publish/Subscribe)** 4. **路由模式(Routing)** 5. **主题…

DVWA靶场第一关--Brute force 新手入门必看!!!

文中涉及讲解burp爆破模块介绍可能不太准确&#xff0c;请大佬批评指正就dvwa靶场而言&#xff0c;两个常见漏洞让我有了新的认知第一个接触的漏洞为弱口令漏洞&#xff0c;常见情况下&#xff0c;人们口中的弱口令可能为“姓名缩写”“123456”“生日简写等”接触了dvwa&#…

完美解决Docker pull时报错:https://registry-1.docker.io/v2/

1、错误描述rootubuntu-database:/opt/dify/docker# docker compose up -d [] Running 9/9✘ api Error context canceled …

用 Python 批量处理 Excel:从重复值清洗到数据可视化

引言日常工作中&#xff0c;经常需要处理多份 Excel 表格&#xff1a;比如合并销售数据、清洗重复的用户信息&#xff0c;最后生成可视化图表。手动操作不仅效率低&#xff0c;还容易出错。这篇文章分享一套 Python 自动化流程&#xff0c;用pandas和matplotlib搞定从数据清洗到…

4.5 点云表达方式——图

(一)定义与原理 图4-5-1 点云图结构

wordpress菜单调用的几种常见形式

在WordPress主题开发里&#xff0c;“菜单”在前端页面中常见的调用/输出形式可以归纳为5种&#xff0c;按出现频率从高到低列给你&#xff0c;并给出最简代码片段&#xff0c;方便直接复制粘贴。 标准菜单位置调用(99%场景) 后台“外观→菜单”里把菜单A指派到菜单位置prima…

linux中pthread_t 的值与top -Hp中线程id值的区别

linux中pthread_t 值与top -Hp中线程id值的区别 #include <stdio.h> #include <pthread.h> #include <thread>void thread_func() {printf("child thread id0x%x\n",pthread_self());while(1){ printf("hello world\n");} }int ma…

Idea集成Jenkins Control插件,在IDEA中触发Jenkins中项目的构建

IDEA可以下一个这个插件 Jenkins Control&#xff0c;直接在idea中触发测试环境项目的部署测试环境API-TOKEN&#xff1a;XXXXXXXXXXXXXXXX&#xff08;在jenkins的首页 - 系统管理 - 管理用户中获取&#xff09;配置号后&#xff0c;测试连接&#xff0c;需要是成功的状态&…

【ARM】CMSIS6 介绍

1、 简介CMSIS是通用微控制器软件接口标准(Common Microcontroller Software Interface Standard ) 的简写。CMSIS 包括API、软件组件、工具及工作流程&#xff0c;主要用于简化软件重用、缩短开发人员学习曲线&#xff0c;加快项目构建和调试&#xff0c;从而使产品更快上市。…

【含文档+PPT+源码】基于SSM的旅游与自然保护平台开发与实现

项目介绍 本课程演示的是一款&#xff1f;&#xff1f;&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 带你从零开始部署运行本套系统 该项目附带的源码资料…

QT6 源,十章绘图(2)画刷 QBrush:刷子只涉及填充颜色,线型,填充图片,以及变换矩阵这几个属性,附源代码带注释。

&#xff08;1&#xff09;本类的继承关系如下 &#xff1a;&#xff08;2&#xff09;本类是支持流运算的 &#xff1a;&#xff08;3&#xff09;本类的构造函数与运算符 operator 函数 &#xff1a;关于本类的构造函数&#xff0c;进行以下测试 &#xff1a;只修改画刷的构…

安科瑞智慧能源管理系统在啤酒厂5MW分布式光伏防逆流控制实践

项目信息 光伏装机1MW&#xff0c;3个并网点&#xff0c;低压接 入配电系统。 要求自发自用、余电不上网。解决方案 通过防逆流保护装置&#xff0c;做到刚性控制&#xff0c; 实现并网柜快速切断&#xff1b;通过防逆流管理系统&#xff0c;做到柔性调节&#xff0c; 实现光伏…

VUE-第二季-02

3.Vue组件化 3.1 什么是组件 (1) 传统方式开发的应用 一个网页通常包括三部分&#xff1a;结构&#xff08;HTML&#xff09;、样式&#xff08;CSS&#xff09;、交互&#xff08;JavaScript&#xff09; 传统应用存在的问题&#xff1a; ① 关系纵横交织&#xff0c;复杂…

【OpenGL】LearnOpenGL学习笔记02 - 绘制三角形、矩形

上接: https://blog.csdn.net/weixin_44506615/article/details/149861824 完整代码&#xff1a;https://gitee.com/Duo1J/learn-open-gl 一、渲染管线 在开始之前&#xff0c;我们先简单了解一下图形渲染管线 在渲染3D物体时&#xff0c;我们常用到的一种几何结构为网格模型…

Mysql的事务是什么?

简单来说&#xff0c;MySQL 实现事务的核心就像是给你的数据库操作加了一套“保险和存档”机制。它确保了你的操作要么全部成功&#xff0c;要么全部失败&#xff0c;并且在面对多人同时操作、系统突然崩溃等情况时&#xff0c;数据依然可靠、准确。 为什么需要事务呢&#xff…

测试开发:Python+Django实现接口测试工具

【测试开发天花板】DjangoVuePyTest打造企业级自动化平台&#xff5c;能写进简历的硬核项目最近被几个公司实习生整自闭了&#xff0c;没有基础&#xff0c;想学自动化又不知道怎么去学&#xff0c;没有方向没有头绪&#xff0c;说白了其实就是学习过程中没有成就感&#xff0c…

TFS-2022《A Novel Data-Driven Approach to Autonomous Fuzzy Clustering》

核心思想 这篇论文的核心思想是提出一种全新的、数据驱动的自主模糊聚类&#xff08;Autonomous Fuzzy Clustering, AFC&#xff09;算法。其核心创新在于&#xff0c;它巧妙地结合了模糊聚类的灵活性和基于中位数&#xff08;medoids&#xff09;聚类的可解释性&#xff0c;并…

ELK是什么

ELK 是一个广受欢迎的开源技术栈&#xff0c;用于实时采集、处理、存储、搜索、分析和可视化海量的日志数据&#xff08;log&#xff09;和机器生成的数据&#xff08;machine data&#xff09;&#xff0c;尤其是在 IT 系统监控、应用故障排查、安全分析和业务智能等领域应用广…

[硬件电路-123]:模拟电路 - 信号处理电路 - 常见的高速运放芯片、典型电路、电路实施注意事项

一、高速运放常见芯片型号及特性高速运放&#xff08;高速运算放大器&#xff09;通常指带宽&#xff08;GBW&#xff09;超过10MHz、压摆率&#xff08;SR&#xff09;高于10V/μs的器件&#xff0c;适用于视频处理、通信系统、高速数据采集等场景。以下是典型芯片及其特性&am…

关于解决WinRiver项目动态XmlElement的序列化与反序列化的问题

关于解决WinRiver项目动态XmlElement的序列化与反序列化的问题 一、WinRiver项目流量汇总XML内容 1.1、索引可变,索引下 XmlElement 元素内容固定 1.2、如何将对象 BottomTrack 的动态内容序列化为 XML ? 1.3、如何将 XML 动态内容反序列化为对象 BottomTrack ? 二、XML 动态…