JUC中创建的组件 多线程使用“哈希表”

news2024/11/26 13:29:47

JUC中创建的组件

JUC中创建的组件这些内容都不太常用,偶尔用到面试的时候,偶尔用到!到时候自行查找即可,本文主要来快速的过一下,留个印象即可~

JUC(java.util.concurrent)和多线程相关的工具类。

1.Callable的用法

非常类似于Runnable(描述了一个任务/一个线程要干啥),Runnable通过run方法描述,返回类型void,但是很多时候,是希望任务要有返回值的,有一个具体的结果产出的!!

call的方法有返回值

写一个代码,创建一个线程,用这个线程计算一下:1+2+3+4+……+1000

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Main {
    public static void main(String[] args) throws ExecutionException,InterruptedException {
        //这只是创建个任务
        Callable<Integer> callable=new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                //Integer 看返回值类型(看实际需要)
                int sum=0;
                for (int i = 1; i <= 1000; i++) {
                    sum=sum+i;
                }
                return sum;
            }
        };
        //还需要找个人,来完成这个任务(线程)
        //Thread不能直接传Callable,需要在包装一层
        FutureTask<Integer> futureTask=new FutureTask<>(callable);
        Thread t=new Thread(futureTask);
        t.start();

        //取结果
        System.out.println(futureTask.get());
    }
}

上述代码的运行结果为:

那么在上述代码中:如何保证调用get()的时候,t线程的call方法是执行完毕了呢??

其实get()和join()类似,都是会阻塞等待~

那么,到目前为止:我们有着以下四种方法来创建线程~

  • 继承 Thread
  • 实现Runnable
  • 基于lambda
  • 实现Callable

ReentrantLock的可重入:

synchronized关键字是基于代码块的方法来控制加锁解锁的!

ReentrantLock则是提供了lock和unlock两个独立的方法来进行加锁解锁的,虽然大部分情况下,使用synchronized就足够了,ReentrantLock也是一个重要的补充

体现在三个方面:

  1. synchronized只是加锁解锁,加锁的时候,如果发现锁被占用,只能阻塞等待,ReentrantLock还提供了一个trylock方法,如果加锁成功,没啥特殊的!如果加锁失败,不会阻塞,直接返回false(让程序员灵活的决定接下来做啥!)
  2. synchronized是一个非公平锁(概率均等,不遵循先来后到)ReentrantLock提供了公平和非公平两种工作模式(在构造方法中,使true——》公平锁)
  3. synchronized搭配wait(),notify()进行等待唤醒,如果多个线程wait()等待同一个对象,notify()的时候是随机唤醒一个!

ReentrantLock则是搭配Condition这个类,这个类也能起到等待通知,可以功能更加强大~

信号量(Semaphore)

停车场外面的一个牌子,显示剩余车位XXX(这就用到信号量)

信号量本质上是一个计数器,描述了当前“可用资源的个数”;

P操作:申请资源,计数器-1,V操作,释放资源,计数器+1

如果计数器已经是0了,继续申请资源,就会阻塞等待~

其实,所谓的“锁”,本质上是计数器为1的信号量

取值只有1和0两种,也叫二元信号量

信号量是更广义的锁,不光能管理非0既1的资源,也能管理多个资源!!

JUC的一些线程安全集合类~

常用的有:ArrayList,LinkList,HashMap,PriorityQueue……线程不安全

如果多线程环境下使用就可能出现问题:

  1. 最直接的方法:使用锁来手动保证!!多个线程去修改Array List此时就可能有问题,就可以给修改操作进行加锁操作!!
  2. 标准库还提供了一些线程安全版本的集合类,如果需要使用ArrayList,则可以使用Vector代替(不建议使用,古老级别)

CopyOnWeriteArrayList支持“写时拷贝”集合类

修改的时候就拷贝一份!!线程安全是多个线程修改不同变量(没加锁)

多线程使用“哈希表”

HaspMap线程不安全肯定不行!!

HashTable线程安全的,也是给关键方法加synchronized(加到方法上,相当于针对this加锁了!)

ConcurrentHashMap推荐方案:

高频面试题:HashTable和ConcurrentHashMap的区别!!(面试高频)

  1. 加锁粒度不同(触发锁冲突的频率)

HashTable是针对整个哈希表加锁,任何的增删改查操作,都会触发加锁,也就都会可能有锁竞争!实际上仔细思考,其实没必要加锁这么勤快!!

HashTable的底层是一个数组+链表

插入元素,根据Key计算hash值——》数组下标,把这个新的元素给挂到对应下标的链表上(Java  Hash Map还会再链表太长的时候,把链表变为红黑树!

如果咱们是两个线程插入元素!

线程1插入的元素对应再下标为1的链表上~

线程2插入的元素对应再下标为2的链表上~

是否存在线程安全问题??两个线程修改不同变量,没啥事,没有线程安全问题!!此时虽然两个操作没有线程安全问题,但是由于synchronized是加到this上的,仍然会针对同一个对象产生锁竞争,产生阻塞等待!!


那么当不只有一把锁的时候:

concurrentHashMap不是只有一把锁了,是每个链表(头节点)作为一把锁!!

每次进行操作,都是针对对应链表的锁进行加锁,操作不同链表就是针对不同的锁进行加锁,不会有竞争!!

该方法导致大部分加锁操作实际上没有锁冲突的,此时,这里的加锁操作的开销就微乎其微了!!

上述内容便是HashTable和ConcurrentHashMap的最大,最核心区别!!

concurrentHashMap是把每个链表的头节点放到synchronized

    void put(String key,String value){
        //先找到对应链表的头节点
        int index=hashCode(key);
        Node head=getHead(index);
        synchronized (head){
            //执行链表插入节点的操作
        }
    }

上述的情况是从Java8开始的,在Java1.7及其之前,concurrentHashMap使用“分断锁”,目的和上述是类似的,相当于是好几个链表共用一把锁(这个设定是不科学的,效率不够高,代码写起来也很麻烦……)


其他方面的改进:

1.concurrentHashMap更重复的利用了CAS机制——》无锁编程!!

有的操作,比如获取/更新元素个数,就可以直接使用CAS完成,不必加锁了!!CAS也能保证线程安全,往往比锁更高效,但是这个东西咱们也不会经常使用!适用范围不像锁那么广泛!!

2.concurrentHashMap优化了扩容机制

HashTable如果元素过多,就会涉及到扩容——》负载因子0.75!!扩容需要重新申请空间,搬运元素(把元素从旧的哈希表上删除,插入到新的哈希表上),如果元素本身非常多,上亿个,搬运一次,成本就很高,就会导致这一次的put()操作就会非常卡顿!!而concurrentHashMap策略——》化整为零,并不会试图一次性的就把所有元素都搬运过去,而是每次只搬运一小部分 ,当put()触发扩容,此时就会直接创建更大的内存空间!!但是,不会直接把所有元素都搬运过去,而是只搬运一小部分(这样的速度还是比较快的!)此时相当于存在两份hash表了,此时插入元素直接往新表插入,删除元素:元素在哪个表的元素,查找:新表旧表都查看!并且每次操作都搬运一部分过去!

多线程比较复杂,应用非常广泛的东西,程序员必须要扎实掌握!

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

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

相关文章

【APUE】文件I/O(系统调用I/O)

目录 1、简介 2、文件描述符的本质 3、文件IO操作 3.1 open 3.2 close 3.3 read 3.4 write 3.5 lseek 4、文件IO与标准IO的区别 5、IO的效率问题 关键补充&#xff1a;进程的内存空间布局 代码区 常量区 全局区 .bss段 .data段 堆区 栈区 6、文件共享 7…

详解【异质图卷积网络 RGCN】回顾:图神经网络问题的三大处理步骤 | 从起源说起,RGCN核心公式解释,两种降低模型参数量/优化的方式,附核心代码实现讲解

书上说了,天下没有不散的宴席,但你别怕,书上还说了,人生何处不相逢。 【纯手工】优质讲解,码字不易,写作不易,走过路过,大家点个赞呗! 🎯作者主页: 追光者♂🔥 🌸个人简介: 💖[1] 计算机专业硕士研究生💖 🌿[2] 2023年城市之星领跑者TOP…

*p 和p区别

*p 和 &p 是在C语言中用于处理指针的两种不同操作。 *p: * 是解引用运算符&#xff0c;用于访问指针所指向的内存地址上的值。如果 p 是一个指针变量&#xff0c;*p 就是该指针所指向的值。举例&#xff1a;如果有 int *p&#xff0c;它是一个指向整数的指针&#xff0c;那…

机器学习西瓜书+南瓜书吃瓜教程第三章学习笔记

本次学习为周老师的机器学习西瓜书谢老师南瓜书Datawhale视频 视频地址 下面为本人的学习笔记&#xff0c;最近很忙还没学多少&#xff0c;之后补&#xff01;&#xff01;&#xff01; u1s1&#xff0c;边看视频边自己手推一遍真的清楚很多&#xff0c;强烈推荐自己手推虽然花…

BUU [HCTF 2018]Hideandseek

BUU [HCTF 2018]Hideandseek 考点&#xff1a; 软连接读取任意文件Flask伪造session/proc/self/environ文件获取当前进程的环境变量列表random.seed()生成的伪随机数种子MAC地址(存放在/sys/class/net/eth0/address文件) 国赛的时候遇见过软连接&#xff0c;这次再来学习一下…

加州法案提议在州一级监管人工智能

加州高级立法者将于周三向州参议院提出一项新的人工智能 (AI) 法案&#xff0c;加强国家和全球监管快速发展技术的努力。 加州参议员斯科特表示&#xff0c;尽管国会多次尝试起草人工智能立法&#xff0c;但加州——硅谷的所在地&#xff0c;世界上大多数顶级人工智能公司都位于…

专治机器学习面试:机器学习各个算法的优缺点!

今天有朋友聊起来&#xff0c;机器学习算法繁多&#xff0c;各个算法有各个算法的特点。以及在不同场景下&#xff0c;不同算法模型能够发挥各自的优点。 今天呢&#xff0c;我把常见的、常用的算法模型进行了一个大概的总结。包括其分支以及各分支的优缺点。 涉及到的算法有…

欢迎参与体素大战活动!

全新的节目即将登陆 The Sandbox 直播流&#xff0c;我们希望你能成为其中的一员&#xff01; 我们正在寻找 20 位 VoxEdit 艺术家来参与这场惊喜的直播活动&#xff0c;本次活动只需要屏幕共享即可。您将在快节奏的环境中进行创作&#xff0c;以竞争「最佳快速设计 Voxel 艺术…

Git学习笔记7

github上多人协助开发演示过程&#xff1a; 张三是项目作者。 李四是一个协同的用户。觉得项目不错&#xff0c;想增加一些功能。 clone与fork的区别&#xff1a; clone&#xff1a;任何人都可以下载作者的整个项目&#xff0c;但是非作者不能push到作者的项目里。&#xff…

【Java 基础篇】Java对象反序列化流详解

在Java编程中&#xff0c;对象序列化和反序列化是常见的操作&#xff0c;用于将对象转换为字节流以便于存储或传输&#xff0c;并从字节流中重新构建对象。本文将重点介绍对象反序列化流的用法和相关概念&#xff0c;帮助基础小白理解这一重要的主题。 什么是对象反序列化&…

javaee之黑马乐优商城4

商品规格与数据结构 下面来说一下数据库的设计与分析 其实对于spu这张表来说&#xff0c;大体设计还是比较好设计的 看一下下面这张图是一个产品的规格参数 上面主体就是一个规格参数&#xff0c;基本信息又是一个规格参数 这里就是涉及到了一个商品的具体信息&#xff0c;sku…

在时代的浪潮中实在前行!实在智能与浪潮通软全面开启战略合作

“新”潮涌动&#xff0c;浪花朵朵。近日&#xff0c;杭州实在智能科技有限公司与浪潮通用软件有限公司签署战略合作协议。双方将加快科研创新&#xff0c;扩大合作领域&#xff0c;共同开拓数智化市场&#xff0c;携手共赢。 浪潮通软平台软件与技术研究院总经理周祥国、实在智…

游戏使用脚本配置HTTP

在游戏世界中&#xff0c;使用脚本工具帮助优化游戏体验已经成为一种普遍现象。但是&#xff0c;是否需要结合代理IP来使用游戏脚本呢&#xff1f;本文将探讨游戏使用脚本时是否需要代理IP的利弊&#xff0c;并分享合规使用脚本的方法。 1. 提高账号安全性&#xff1a; - 通过…

知识图谱的搭建

知识图谱搭建最重要的核心在于对业务的理解以及对知识图谱本身的设计&#xff0c;这就类似于对于一个业务系统&#xff0c;数据库表的设计是至关重要的&#xff0c;而这种设计师根据业务及未来场景的变化预估不断探索得出的。 一个完整的知识图谱的构建包含以下几个步骤&#…

Spring 中的Aware接口有什么作用

文章目录 0.前言1.什么是Aware接口2.Aware接口的设计目的3.详解3.1. ApplicationContextAware我们举个例子来说明 3.2. BeanFactoryAware3.3. BeanNameAware3.4. ServletContextAware3.5. MessageSourceAware3.6. ResourceLoaderAware 4.参考文档 0.前言 背景&#xff1a; 最近…

Centos7完全离线环境安装Nvidia Tesla A100 40G显卡驱动(含CUDA Toolkit)和Anaconda3虚拟环境

公司一台完全离线环境的服务器刚装了Nvidia Tesla A100 40G显卡&#xff0c;自己摸索着将显卡驱动在完全离线环境下安装成功&#xff0c;这里记录一下。 一、下载Centos7适配的Nvidia Tesla A100 40G显卡驱动 在Nvidia官网下载Centos7适配的显卡驱动&#xff0c;CUDA Toolkit…

idea(第一次)启动项目,端口变成了8080

先上配置 server:port: 9569 spring:profiles:active: dev 该排查的问题也都没问题&#xff0c;重启idea也试过了&#xff0c;还是8080 解决办法&#xff1a;点击右侧的maven ,左上角的重新导入 reimport all maven projects 我又没有改动pom文件&#xff0c;居然还要点这…

玩机教程:阿里云无影云电脑怎么使用?

阿里云无影云电脑即无影云桌面&#xff0c;云电脑如何使用&#xff1f;云电脑购买后没有用户名和密码&#xff0c;先创建用户设置密码&#xff0c;才可以登录连接到云桌面。云桌面想要访问公网还需要开通互联网访问功能。阿里云百科来详细说下阿里云无影云电脑从购买、创建用户…

Android 13.0 SystemUI下拉状态栏背景增加高斯模糊背景

1.概述 在13.0的产品开发中,发现现在很多产品都是高斯模糊背景的,这种高斯模糊背景看起来效果很不错,产品开发需要SystemUI下拉状态栏背景也是高斯模糊背景,所以就要来实现下拉状态栏高斯模糊背景 2.SystemUI 下拉状态栏背景增加高斯模糊背景核心类 frameworks/base/pack…

python后端和前端通过websocket通讯发消息最小案例,十分钟看懂

前端和后端通过websocket实现发送消息案例&#xff0c;用于理解websocket&#xff0c;服务端可以主动给客户端发送消息&#xff0c;而且是长连接&#xff0c;比http效率高&#xff0c;因为http要不断地创建和销毁socket实例&#xff0c;导致压力很大。websocket一次创建&#x…