javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类

这篇具有很好参考价值的文章主要介绍了javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类,Java,java-ee,java

T04BF

👋专栏: 算法|JAVA|MySQL|C语言

🫵 小比特 大梦想

此篇文章与大家分享多线程专题的最后一篇文章:关于JUC常见的类以及线程安全的集合类
如果有不足的或者错误的请您指出!

3.JUC(java.util.concurrent)常见的类

3.1Callable接口

Callable和Runnable一样,都是用来描述一个任务的
但是区别在于 ,用Callable描述的任务是有返回值的,而通过Runnable描述的任务是没有返回值的(即run方法的返回值是void)
通过Runnable,要想获取到"返回值",只能通过一些特定的手段
javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类,Java,java-ee,java
但是这个方法,主线程和 t线程的耦合太大了
而Callable就是为了会更优雅的解决上面的问题
javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类,Java,java-ee,java
但是Thread并没有提供这样的构造方法
我们可以将callable传入FutureTask
javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类,Java,java-ee,java

3.2 RentrantLock

表示可重入的锁
相对于我们常用的Synchronized,ReentrantLock是"手动"进行加锁和解锁的

    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        //加锁
        lock.lock();
        //解锁
        lock.unlock();
    }

但是这种就容易"漏掉"解锁操作,就会出现大问题,因此我们经常搭配finally使用
javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类,Java,java-ee,java
既然这个这么麻烦,那还有存在的价值嘛??
实际上价值还是很大的

ReentrantLock提供了公平锁的实现

javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类,Java,java-ee,java
如果传入true就是表示公平锁,传入false / 不传 就是非公平锁

ReentrantLock提供了tryLock

所谓tryLock就是尝试加锁
如果在遇到锁已经被占有了,那就直接返回
而相比于synchronized则是阻塞等待
另外,除了直接返回外,tryLock还提供了带等待超时的版本

Condition

Synchronized是搭配 wait 和 notify使用
而ReentrantLock是搭配Condition使用
实际上Condition比wait和notify更加智能,因为它可以指定唤醒那个线程

3.3 Semaphore

表示信号量,用来表示"可用资源"的个数,本质上就是个计数器
围绕信号量主要有两个基本操作
(1)P操作,即申请资源,计数器 -1;
(2)V操作,即释放资源,计数器+1;
javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类,Java,java-ee,java
但我们申请的资源超过信号量本身的大小们,就会阻塞等待,直到其他地方释放资源
javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类,Java,java-ee,java
那么当资源数目为1的话,就可以当成锁来使用了
javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类,Java,java-ee,java

因为如果信号量有0 1两个取值,此时就是"二元信号量",本质上就是一把锁

3.4CountDownLatch

表示同时等待多个线程结束
是一个比较实用的工具
当我们把一个任务拆解成多个线程来完成时,就可以利用这个工具类来判断,任务整体是否完成了
javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类,Java,java-ee,java
此时的执行结果就是:
javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类,Java,java-ee,java
await会阻塞等待,一直到countDown调用的次数,和构造方法指定的次数一致的时候,await才会返回

而await不仅仅能够替代join,假设现在有1000个任务要交给4个线程来使用,那么如何判断1000个任务已经执行结束??就可以使用countDownLatch来判断

4.线程安全的集合类

原来的集合类.比如ArrayList,LinkedList,HashMap等等,都是线程不安全的
而Vector自带了synchronized,Stack继承了ector,HashTable也是自带的synchronized,在一定程度上是线程安全的

但是不能说太绝对,还是要具体情况具体分析 就比如可能出现下面这种情况:
javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类,Java,java-ee,java
就比如上述代码,线程1执行到if条件判断后,线程2把vector给清空了,就会出现bug

如果需要用到其他的类,就需要手动加锁,来保证线程安全,但不同情况下加锁的情况是不一样的,手动加锁是比较麻烦的

标准库就提供了一些具体的解决方法

4.1多线程环境下使用ArrayList

4.1.1Collection.synchronizedList(new ArrayList)

这种方法就相当于给这些集合类套了一层壳,壳上对集合类里面的一些关键方法加上了锁,起到了类似Vector的效果

4.1.2CopyOnWriteArrayList

利用的是"写时拷贝"的思想
假设我们现在有一组数据为1 2 3 4,此时某个线程对数据进行了修改,就把2 修改成200,3修改成300,但是在修改的时候有别到线程在读,如果直接修改就有可能出现2,300这样的中间数据
而写时拷贝就是将原来的数据集拷贝一份,这样修改的时候是在新拷贝的数据集上修改的,而读的时候是在旧的数据集上读的
等到修改完后,就用新的数据集的引用代替原来旧的数据集的引用
这样的过程中,不会出现任何加锁和阻塞等待,也保证读数据不会出现"错误的数据"

这种操作实际上实用性非常高,就比如有的服务器需要更新配置文件 / 数据文件,就可以采取上述策略

4.2多线程使用队列

直接使用BlockingQueue即可

4.3多线程使用哈希表

HashMap是线程不安全的,而HashTable是带锁的
但是实际上HashTable并不推荐使用
因为HashTable本质上就是简单粗暴将每一个方法都进行加锁,就相当于针对了this加锁,此时只要针对HashTable上的元素进行操作,就都会涉及到锁
推荐使用的是 ConcurrentHashTable
它的优点就在于:
(1)采用锁桶的方式,来代替之前的"全局一把锁"
javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类,Java,java-ee,java
此时如果两个线程针对的是不同链表上的元素进行操作,是不会涉及到锁冲突的
而本身,操作两个链表上的元素,不涉及公共变量,是不会有线程安全问题的
进行这样的操作实际上收益是很多的
因为在一个Hash表里面,桶的数量是很多的,此时按照我们上面的操作进行加锁,大部分情况是可以避免锁冲突的

那么好像锁多了,锁对象就多了是不是更加麻烦了??
实际上,由于java中任何的对象都可以作为锁对象,我们只需将每一个链表的头结点作为锁对象即可

(2)引入CAS机制
实际上即使是上面的操作,也不能保证线程安全
像哈希表的size,即使你插入的是不同链表的元素,修改的时候也会涉及到多线程修改同一个变量
此时引入了CAS机制,通过CAS来修改size,也就不涉及加锁操作了

(3)针对扩容进行了特殊优化

在哈希表中,如果发现负载因子太大了,就需要扩容,而扩容是一比较低效的操作,普通的hash表如果要在一次put完成整个扩容操作,就会使得put非常卡,如果平时使用put假设是1ms,但某次put执行了1000ms,就会造成不好的体验

ConcurrentHashMap进行的实际上是"化整为零",在扩容的时候会搞两份空间

一份是扩容前的空间,一份是扩容后的空间

接下载每次进行哈希表的基本操作的时候,都会将一部分数据从旧空间搬到新空间

不是一口气搬完,分多次搬

搬的过程中,

如果进行的是插入操作,那就插到新的空间里面

如果是删除,那么旧的新的都会删除

如果是查找,那么旧的新的都要查找一遍

就是"重哈希"过程,重哈希过程结束的标志通常是所有元素都被成功地移动到了新的空间中,并且旧空间中不再包含任何元素。

感谢您的访问!!期待您的关注!!!

javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类,Java,java-ee,java文章来源地址https://www.toymoban.com/news/detail-857309.html

T04BF

🫵 小比特 大梦想

到了这里,关于javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【JavaEE初阶】 线程安全

    线程安全是多线程编程是的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且准确的执行,不会出现数据污染等意外情况。上述是百度百科给出的一个概念解释。换言之,线程安全就是某

    2024年02月08日
    浏览(46)
  • JavaEE 初阶篇-深入了解进程与线程(常见的面试题:进程与线程的区别)

    🔥博客主页: 【 小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录         1.0 进程概述         2.0 线程概述         2.1 多线程概述         3.0 常见的面试题:谈谈进程与线程的区别         4.0 Java 实现多线程的常见方法         4.1 实现多线程方法 - 继承

    2024年04月13日
    浏览(36)
  • 【JavaEE初阶】多线程进阶(五)常见锁策略 CAS synchronized优化原理

    乐观锁:预测锁竞争不是很激烈。 悲观锁:预测锁竞争会很激烈。 以上定义并不是绝对的,具体看预测锁竞争激烈程度的结论。 轻量级锁加锁解锁开销比较小,效率更高。 重量级锁加锁解锁开销比较大,效率更低。 多数情况下,乐观锁也是一个轻量级锁。 多数情况下,悲

    2024年02月03日
    浏览(34)
  • 【JavaEE】线程安全的集合类

    作者主页:paper jie_博客 本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。 本文于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将基础知识一网打尽,希望可以帮到读者们哦。 其他专栏:《MySQL》《C语言》

    2024年01月20日
    浏览(31)
  • Java - JUC(java.util.concurrent)包详解,其下的锁、安全集合类、线程池相关、线程创建相关和线程辅助类、阻塞队列

    JUC是java.util.concurrent包的简称,在Java5.0添加,目的就是为了更好的支持高并发任务。让开发者进行多线程编程时减少竞争条件和死锁的问题 java.lang.Thread.State tools(工具类):又叫信号量三组工具类,包含有 CountDownLatch(闭锁) 是一个同步辅助类,在完成一组正在其他线程中

    2024年02月05日
    浏览(29)
  • 【多线程初阶】Thread类常见方法以及线程的状态

    本文是属于多线程初阶内容系列的, 如果还没有学习过之前文章的, 请先移步博主的之前的文章进行学习, 本文就是在学会线程的创建后, 再带大家认识一下 Thread 类以及其常见的方法, 再给大家讲解一下线程都有哪些状态. 关注收藏, 开始学习吧🧐 通过我们上篇文章的学习, 我

    2024年02月16日
    浏览(31)
  • JavaEE 初阶篇-深入了解多线程安全问题(指令重排序、解决内存可见性与等待通知机制)

    🔥博客主页: 【 小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录         1.0 指令重排序概述         1.1 指令重排序主要分为两种类型         1.2 指令重排序所引发的问题         2.0 内存可见性概述         2.1 导致内存可见性问题主要涉及两个方面      

    2024年04月15日
    浏览(38)
  • 【Java|多线程与高并发】JUC中常用的类和接口

    JUC是Java并发编程中的一个重要模块,全称为 Java Util Concurrent (Java并发工具包),它提供了一组用于多线程编程的工具类和框架,帮助开发者更方便地编写线程安全的并发代码。 本文主要介绍 Java Util Concurrent 下的一些常用接口和类 Callable接口类似于Runnable. 有一点区别就是

    2024年02月12日
    浏览(25)
  • java基础之线程安全问题以及线程安全集合类

    当多个线程同时访问同一个临界资源时,原子操作可能被破坏,会导致数据丢失, 就会触发线程安全问题 临界资源: 被多个线程同时访问的对象 原子操作: 线程访问临界资源的过程中不可更改和缺失的操作 互斥锁 每个对象都默认拥有互斥锁, 该锁默认不开启. 当开启互斥锁之后

    2024年01月18日
    浏览(37)
  • 【JavaEE】JUC(Java.util.concurrent)常见类

    经过前面文章的学习我们大致了解了如何实现多线程编程和解决多线程编程中遇到的线程不安全问题, java.util.concurrent 是我们多线程编程的一个常用包,那么今天我将为大家分享 java.util.concurrent 包下的其他几种常见的类。 ReentrantLock 是可重入互斥锁,跟 synchronized 定位是类似

    2024年02月08日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包