多线程进阶:Callable和JUC的常见类

Callable

这是一个接口,类似于Runnable。

Runnable用来描述一个任务,描述的任务没有返回值。

Callable也是用来描述一个任务,描述的任务是有返回值的。

如果需要使用一个线程单独的计算出某个结果来,此时用Callable是比较合适的。

在new一个Callable之后,需要重写一个方法。就相当于是重写Runnable的Run方法,run方法的返回值是void,这里的call方法返回值是泛型参数。

 我们需要FutureTask的帮助:

 这个FutureTask就相当于一个未来的任务,类似于我们吃麻辣烫时,给我们叫号牌。等到麻辣烫做好后,会通过叫号牌来叫我们。

Future表示一个任务的周期,并提供了相应的方法来判断是否已经完成或者取消,以及获取任务的结果和取消任务。

FutureTask实现了RunnableFuture接口,RunnableFuture接口又实现了Runnable接口和Future接口。所以FutureTask既可以被当做Runnable来执行,也可以被当做Future来获取Callable的返回结果

 和Runnable相比,Callable也是创建线程的一个方式,callable解决的是代码好不好看的问题,而不是结果对不对的问题。runnable也能得出结果,但是代码看起来比较乱。

ReentrantLock

这是标准库给我们提供的另一种锁,也是可重入锁。

synchronized是直接基于代码块的方式来加锁解锁的。

ReentrantLock更传统,使用了lock和unlock方法来加锁。

乍一看可能没什么问题,但是这样子加锁解锁可能会导致unlock执行不到。

那如果是lock后多用几个条件限制呢?

如果这中间存在return或者异常都可能导致unlock不能顺利执行~

建议的用法:

把unlock放到finally中。

try 关键字最后可以定义 finally 代码块。 finally 块中定义的代码,总是在 try 和任何 catch 块之后、方法完成之前运行。

正常情况下,不管是否抛出或捕获异常 finally 块都会执行。

 这样就能保证unlock一定会执行。

上面的是ReentrantLock的劣势,但是也是有优势的:

1.ReentrantLock提供了公平锁版本的实现

ReentrantLock reentrantLock = new ReentrantLock(true);

2.对于synchronized来说,提供的加锁操作就是死等,只要获取不到锁,就一直一直阻塞等待~

ReentrantLock提供了更灵活的等待方式:tryLock

reentrantLock.tryLock();

无参数版本,能加锁就加,加不上就放弃。

有参数版本,指定了超时时间,加不上锁就等一会,如果等一会时间到了也没加上就放弃等待。

3.ReentrantLock提供了一个更强大,更方便的等待通知机制。
synchronized搭配的是 wait notify。notify的时候是随机唤醒一个wait的线程。ReentrantLock搭配一个Condition类,进行唤醒的时候可以唤醒指定的线程。

总结:虽然ReentrantLock有一定的优势,但是实际开发中,大部分情况下还是用的synchronized。

原子类

原子类内部用的是CAS,所以性能要比加锁实现i++要高很多

虽然CAS确实是更加高效的解决了线程安全问题,但是CAS不能代替锁,CAS的适用范围是有限的,不像锁的适用范围那么广。

信号量 Semaphore

这里的信号量和操作系统上的信号量是同一个东西,只不过这里的信号量是Java把操作系统原生的信号量封装了一下。

信号量这个东西在我们生活中经常可以见到:

信号量就是这个计数器,描述了“可用资源的个数”

P操作:申请一个可用资源,计数器就要-1

V操作:释放一个可用资源,计数器就要+1

P操作如果要是计数器为0,继续P操作,就会出现阻塞操作。直到下一个V操作以后才能继续进行P操作。

实际开发中,虽然锁是最常用的,但是信号量也是会偶尔用到的,主要还是看实际的需求场景。

CountDownLatch

有一场跑步比赛,开始时间是明确的(裁判的发令枪),但是结束时间是不明确的(所有的选手都冲过终点线),为了等待这个跑步比赛结束,就引入了这个CountDownLatch。

有两个方法:

1.await(wait是等待,a =>all)主线程来调用这个方法

2.countDown表示选手冲过了终点线

例如,有四个选手进行比赛,初始情况下,调用await就会阻塞,就代表进入了比赛时间,每个选手冲过终点的时候,都会调用countDown方法。

前三次countDown,await没有任何影响,第四次调用countDown,await就会被唤醒,返回(解除阻塞),此时就可以认为是整个比赛都结束了。

多线程环境下使用ArrayList

1.自己加锁,使用synchronized或者ReentrantLock

2.Collections.synchronizedList 这里面会提供一些ArrayList相关的方法,同时是带锁的。

3.CopyOnWriteArrayList,简称为COW,也叫做写时拷贝。

针对这个ArrayList进行读操作,不做任何额外的工作;

如果进行写操作,则拷贝一份新的ArrayList,针对新的进行修改。修改的过程中如果有读的操作,那么就继续读旧的这一份数据。当修改完毕了,使用新的替换旧的。

这种方案优点:不需要加锁

              缺点:要求这个ArrayList不能太大,只是适用于数组比较小的情况下

多线程使用哈希表[重点、难点]

HashMap是线程不安全的,HashTable是线程安全的(因为给关键方案加了synchronized)

但是更推荐使用的是ConcurrentHashMap,这是更加优化的线程安全哈希表。

在这有几个重点:

1.ConcurrentHashMap进行了哪些优化?

2.比HashTable好在哪里?

3.和HashTable之间的区别是什么?

最大的优化之处:ConcurrentHashMap相比于HashTable大大缩小了锁冲突的概率,把一把大锁,转换成多把小锁了。

HashTable会在整个链表上加锁。 

ConcurrentHashMap的做法是,每个链表有各自的锁,而不是共用一个锁

具体来说,就是用每个链表的头结点,作为锁对象。这样两个线程不针对同一个对象加锁,就不会有锁竞争。

JDK1.7和之前

但是呢,ConcurrentHashMap做了一个激进的操作:

针对读操作不加锁,只针对锁操作加锁。

并且,ConcurrentHashMap内部充分利用了CAS,通过这个来进一步削减加锁操作的数目。

针对扩容,采取“化整为零”的方式

HashMap/HashTable扩容:

创建一个更大的数组空间,把旧的数组上的链表上的每个元素搬运到新的数组上(删除+插入)

这个扩容操作会在某次put的时候进行触发,如果元素个数特别多,就会导致这样的搬运操作比较耗时。(比如某次put的时候,某个用户就卡了)

ConcurrentHashMap扩容:

每次搬运一小部分元素,创建新的数组,旧的数组也保留。每次put操作,都往新数组上添加,同时进行一部分搬运(把一小部分旧的元素搬运到新数组上)

每次get的时候,把新旧数组都查询,remove的时候,把旧数组的元素删了就行了

经过一段时间之后,所有的元素都搬运好了,再释放旧数组。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

爬虫异常处理实战:应对请求频率限制和数据格式异常

作为一名资深的爬虫程序员,今天我要和大家分享一些实战经验,教你如何处理爬虫中的异常情况,包括请求频率限制和数据格式异常。如果你是一个正在进行网络爬虫开发的开发者,或者对异常处理感兴趣,那么这篇文章将帮助你更…

【李沐深度学习笔记】基础优化方法

课程地址和说明 基础优化方法p2 本系列文章是我学习李沐老师深度学习系列课程的学习笔记,可能会对李沐老师上课没讲到的进行补充。 基础优化方法 在讲具体的线性回归实现之前,要先讲一下基础的优化模型的方法 梯度下降 当模型没有显示解&#xff08…

Rust之自动化测试(二):控制测试如何运行

开发环境 Windows 10Rust 1.72.1 VS Code 1.82.2 项目工程 这里继续沿用上次工程rust-demo 控制测试如何运行 正如cargo run编译您的代码,然后运行生成的二进制文件一样,cargo test在测试模式下编译您的代码,然后运行生成的测试二进制文件…

《计算机网络》——应用层

2.1 应用层协议原理(P54) 研发网络应用的核心是写出能够运行在不同端系统和通过网络彼此交流的程序。 2.1.1 网络应用程序体系结构 两种主流的应用体系结构:客户-服务器体系结构、对等体系结构。 客户-服务器体系:服务器是一个…

MeterSphere v2.10.X-lts 双节点HA部署方案

一、MeterSphere高可用部署架构及服务器配置 1.1 服务器信息 序号应用名称操作系统要求配置要求描述1负载均衡器CentOS 7.X /RedHat 7.X2C,4G,200GB部署Nginx,实现负载路由。 部署NFS服务器。2MeterSphere应用节点1CentOS 7.X /RedHat 7.X8C,16GB,200G…

二叉树题目:翻转等价二叉树

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题:翻转等价二叉树 出处:951. 翻转等价二叉树 难度 4 级 题目描述 要求 对于二叉树,我们可以定义如下翻转操作:选…

【算法专题突破】二分查找 - x 的平方根(18)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后: 1. 题目解析 题目链接:69. x 的平方根 - 力扣(LeetCode) 这道题就是求算数平方根, 要注意的点是他只需要保留整数部分,小数部分会舍去 2. 算法…

【HUAWEI】trunk和access两种链路模式实例

目录 🥮0.写在前面 🍣基本操作命令 🍣常见视图命令 🥮1、trunkaccess 🍣1.1、拓扑图 🍣1.2、操作思路 🍣1.3、配置操作 🍡1.3.1、LSW1配置 🍡1.3.2、LSW2配置 &#x1f3…

单列集合顶层接口Collection

🐌个人主页: 🐌 叶落闲庭 💨我的专栏:💨 c语言 数据结构 javaEE 操作系统 Redis 石可破也,而不可夺坚;丹可磨也,而不可夺赤。 集合体系结构 一、单列集合顶层接口Collect…

全面提升AD域安全认证 | 竹云IDaaS

传统的微软Active Directory目录已无法适应企业多样化的业务需求,借助身份云您可以快速整合企业本地、云端资源,从而使AD域管理变得更简单、安全、高效。 企业面临的挑战 AD域无法整合现代化系统 AD域仅支持 LDAP 、Kerberos 协议,不能整合…

数据结构-----串(String)详解

目录 前言 1.串的定义 相关类型 2.串的储存结构 顺序储存表示 堆分配储存表示 块链储存表示 3.串的操作方式 4.串的匹配算法 (1)BF算法 过程原理 代码实现(C/C) 算法分析 (2)KMP算法 过程…

红米note13 秒解锁BL 跳过168 秒解锁BL,红米Redmi Note 13 Pro+ 系列 无需等待168小时,刷入magisk教程 刷机包下载

最近入手了一台红米note13,发现需要等待168小时才能解锁BL,这让我感到非常困扰。不过,经过一番研究,我发现了一个秒解锁BL的方法,无需等待168小时,而且还可以刷入magisk,非常方便。 首先&#x…

【NetEQ】读 《白话解读 WebRTC 音频 NetEQ 及优化实践》学习笔记

白话解读 WebRTC 音频 NetEQ 及优化实践webrtc 的重要模块 官方文档 :转载请标明出处:大神翻译 大神地址 : https://blog.csdn.net/lhl_blog/article/details/10993605GIPS NetEQ概述 GIPS NetEQ是一项专为IP电信系统开发的高级语音质量处理技术,其能够在大幅提高语音质量的…

【Ubuntu18.04】Autoware.ai安装

Autoware.ai安装 1 ROS安装2 Ubuntu18.04安装Qt5.14.23 安装GCC、G4 Autoware安装与编译4.1 针对Ubuntu 18.04 / Melodic的依赖包安装4.2 Autoware环境搭建4.3 运行 Autoware4.4 ROSBAG Demo 1 ROS安装 参考笔者的博客即可:【ROS】Ubuntu18.04安装Ros 2 Ubuntu18.…

mock.js与组件通信之总线的讲解

目录 一Mock.js 1.1简介 1.2 安装配置Mock.js 1.3 mock.js的使用 二. 组件通信之总线 2.1 总线的简介 2.2 总线的使用-以导航栏的收进为例 好啦今天的分享就到这啦!! 一Mock.js 1.1简介 Mock.js 是一个用于生成随机数据的 JavaScript 库。它可以模拟…

蓄水池抽样算法

题目:在一个源源不断的数据流中,会吐出带有编号的球,现在问你 在不知道具体有多少个球的情况下,如何等概率的抽出10个球? 例题:leetcode 382题 应用场景:比如在某个游戏的抽奖活动中&#xff…

vue点击pdf文件直接在浏览器中预览文件

好久没有更新文章了,说说为什么会有这篇文章呢,其实是应某个热线评论的要求出的,不过由于最近很长一段时间没打开csdn现在才看到,所以才会导致到现在才出。 先来看看封装完这个预览方法的使用,主打一个方便使用&#x…

Purple-Pi-OH Linux SDK编译手册

一、 SDK下载 1.1 源码下载 在官网下载Purple-Pi-OH的的相关资料以及Linux SDK: 链接:Purple Pi OH-深圳触觉智能科技有限公司 1.2 源码解压 由于SDK打包后体积较大,我们在上传到百度云盘前把SDK包按照4GB大小分割了,因此下载…

基于物联网的农村地区智能微电网系统(Simulink)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

肖sir__mysql中数据库后端无法展示

mysql中数据库后端无法展示: 错误现象 解决方法: mysql中数据库后端无法展示:my.cnf (5,7数据库) 在 mysql 配置文件中加入: sql_modeNO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 或者重启数据库