3.10多线程

news2024/11/26 11:50:56

一.常见锁策略

1.悲观锁 vs乐观锁

体现在处理锁冲突的态度

①悲观锁:预期锁冲突的概率高

所以做的工作更多,付出的成本更多,更低效

②乐观锁:预期锁冲突的概率低

所以做的工作少,付出的成本更低,更搞笑

2.读写锁 vs 普通的互斥锁

①普通的互斥锁,只有两个操作 加锁和解锁

只有两个线程针对同一个对象加锁,就会产生互斥

②读写锁:有三个操作

针对读锁和读锁之间,是不存在互斥的关系--->因为多线程同时读一个变量,不会有线程安全的问题

读锁和写锁之间,写锁和写锁才需要互斥

而且很多场景中,都是读多写少

3.重量级锁 vs 轻量级锁

是为了处理锁冲突的结果

重量级锁 做了更多的事情,开销大,轻量级锁反之亦然

大多数情况下,悲观锁一般都是重量级锁,乐观锁一般都是轻量级锁

比如: 在使用的锁中,如果锁是基于内核的一些功能来实现的(比如调用了操作系统提供的mutex接口).一般认为这是重量级锁

如果锁是纯纯用户态实现的,一般认为这是轻量级锁,因为用户态的代码更可靠,也更高效

4.挂起等待锁 vs 自旋锁

①挂起等待锁:通过内核的一些机制来实现的.往往比较中 [重量级锁的一种典型实现]

②自旋锁 : 往往是通过用户态代码来实现的,往往比较轻,[轻量级锁的一种典型实现]\

5.公平锁 vs 非公平锁

公平锁:多个线程在等待一把锁的时候谁是先来的,谁就能先获取到这个锁(遵守先来后到

非公平锁:多个线程在等待一把锁的时候不遵守先来后到,每个等待的线程获取到锁的概率是均等的

对于操作系统来说->线程之间的调度是随机的(机会是均等的) .操作系统提供的mutex这个锁.就是属于非公平锁

6.可重入锁 vs 不可重入锁

可以嵌套加锁,就是可重入锁,会死锁的就是不可重入锁

7.synchronized(面试

1)即是一个乐观锁.也是一个悲观锁(根据锁竞争的激烈程度,自适应)

2)不是读写锁,只是一个普通互斥锁

3)既是一个轻量级锁,也是一个重量级锁,(根据锁竞争的激烈程度,自适应)

4)非公平锁 5)可重入锁

二.CAS

compare(比较) and swap(交换)

1.定义

CAS锁:拿着寄存器或者/某个内存的值和另外一个内存的值进行比较,如果值相同了,就交换

伪代码

CAS:提供一个单纯的CAS指令,通过这一条指令,就完成上述伪代码描述的过程

CAS指令:如果上述伪代码的过程只用一条做完,就是原子性,这个时候就是线程安全了

2.作用

1)基于CAS能够实现原子类

(java标准库里提供了一组原子性,针对常用的int.long,,int[]进行了封装,基于cas方式修改,并且线程安全

这段代码是不存线程安全的问题

基于CAS实现的++操作

因为这里既能保证线程安全,又能比synchronized高效

synchronized会涉及到锁的竞争,又要涉及线程的阻塞等待

这里的oldvalue变量,实际实际上可能使用一个寄存器来存的

这个赋值操作就相当于把数据从内存读到寄存器中(load

判定一下当前内存的值是不是和刚刚寄存器取到的值一直

如果判定成功,那就把value设为oldvalue+1.并返回true 循环结束

如果判定失败,继续下次循环,返回true;下次循环还是要先读一下value

这两行代码之间,很有可能有其他线程修改了value的值

为什么上述++操作线程安全

load

cas

2).基于CAS实现自旋锁

自旋锁是一个轻量级锁,也可以视为一个乐观锁

这把锁虽然没能够立即拿到,预期很快就能拿到(假设锁冲突不激烈)

3.ABA问题

1)定义

CAS中的关键就是先比较再交换

比较其实在比较当前值和旧值是否相同

把这两个值相同,就视为中间没有发生改变

但是这句话有漏洞,可能当前值和旧值相同的情况是因为变了然后又变回来了, 这就是ABA

2.案例

举例:ABA产生的BUG

假设小红账户余额 100 他想要取50

当按下取钱操作的时候,机器卡了一下,小红一紧张多按了一下取款

这就相当于 一次取钱操作 执行了两遍 (两个线程,并发的去执行这个取钱操作)

预期是只能取成功一次

如果基于CAS来实现的话

本来应该没问题

第二个线程再比较的时候就会发现,读到的100和原本的50不一样,就会不操作了

但是在取款的一瞬间,小红额度朋友给他转账了50.这个时候就会触发的ABA问题

这个时候第二个线程就会发现还是100.于是又扣了50

3)解决方法

引入版本号

这个版本号只能变大,修改变量的时候,比较的不是变量而是比较版本号

当引入版本号以后,t2再次尝试进行这里的比较版本操作

就会发现版本的旧值和当前的值并不匹配,就直接放弃修改

或者加入时间戳

看当前读到的内存改变的时间戳有没有变化

三.synchronized锁优化机制

只考虑1.8情况

1.锁膨胀/锁升级

体现了synchronized能够"自适应"这样的能力

偏向锁:并不是真的加锁,只是做了个标记.带来的好处就是后续没有竞争额时候,就避免了加锁解锁的开销

比如在大学校园里,大家都很讲素质,所以我的自行车都不锁->我只是在上面刻了我的名字做个标记

但是有一天好几个人的自行车都丢了,.开始有竞争的现象.我就开始加锁.进入轻量级锁

2.锁粗化/锁细化

此处的粗细指的是"锁的粒度"---->加锁代码涉及到的范围,范围越大,就认为锁的粒度越粗.反之亦然

锁粒度细 并发高

锁粒度粗.加锁解锁的开销就小

但是编译器会优化,如果某个地方代码所太细了,就会进行自动粗化

如果加锁之间间隔少(中间的代码少) 就很可能触发这个优化

比如:我给老师打电话,让他帮我请假.然后又打电话说我要出校,然后紧接着又打电话说我想借钱

每次给老师打电话都是给老师加锁,老师都不能接其他人的电话,加锁解锁开销大 粒度太细

于是可以粗化,我一次性说完.再挂电话

3.锁消除

有时候不小心加锁了

编译器发现这个锁没必要就会自动消除

比如StringBuffer Vector 在标准库里都进行了加锁操作

如果在单线程用到了上述的类,编译器会自动解锁.

四.java中的JUC

JUC ------java.util.concurrent

concurrent 并发的

1.Callable

是一个interface 也是一种创建线程的方式

因为Runnable 不太适合让线程计算一个结果

而如果用Callable就比较容易

    public static void main1(String[] args) throws InterruptedException {
        Result result=new Result();
        Thread t=new Thread(){
            @Override
            public void run() {
                int sum=0;
                for (int i = 0; i < 100; i++) {
                    sum+=i;
                }
                synchronized (result.locker){
                        result.sum=sum;//如果不加锁额度话,这是一个写操作,可能会导致线程不安全的情况,需要加锁
                        result.locker.notify();
                }
            }
        };
        t.start();
        synchronized (result.locker){
            while(result.sum==0){
                result.locker.wait();
            }
        }//加锁,直到赋值了才可以唤醒才可以往下执行
        System.out.println(result.sum);//这里还需要创建一个实例让他们的sum互相传
    }
    public static void main2(String[] args) {
        //构建一个类来描述任务
        Callable<Integer> callable=new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum=0;
                for (int i = 0; i < 100; i++) {
                    sum+=i;
                }
                return sum;
            }
        };
        //因为线程的构造方法不能识别callable 需要创建一个类来识别,
        FutureTask<Integer> task=new FutureTask<>(callable);
        Thread thread=new Thread(task);
        thread.start();
        //凭借task能执行
        //如果线程里的任务没执行完,task.get(就会一直阻塞,直到任务完成
        try {
            System.out.println(task.get());
        } catch (InterruptedException e) {
            e.printStackTrace();//这是任务没执行完阻塞
        } catch (ExecutionException e) {
            e.printStackTrace();//这是任务出错执行
        }
    }

2.ReentrantLock

可重入锁,注意synchronized也是可重入锁

1)基础用法

lock()

unlock()

把加锁和解锁两个操作给分开了

这中分开额度做法不太好,容易出现死锁

当出现多个线程竞争同一把锁的时候就会阻塞

2)与synchronized区别(面试)

1.synchronized是一个关键字(背后的逻辑是由JVM实现的也就是c++代码)

ReentrantLock是标准库里的一个类 背后的逻辑是java代码写的

2,synchronized不需要手动释放锁,出代码块,锁自动释放,

ReentrantLock必须要手动释放锁,要谨防忘记释放

3.synchronized是一个非公平锁

ReentrantLock提供了非公平锁和非公平锁 在构造方法中,指定参数来 默认是false

4.synchronized如果竞争锁额度时候失败,就会阻塞等待

ReentrantLock不仅可以阻塞等待,还可以trylock 失败了直接返回

5.synchronized衍生出来的等待机制,是wait notify 功能是相对有限的

ReentrantLock衍生出来的等待机制,是Condition.功能比较丰富

3.Semaphore

信号量 是一个更广义的锁

是锁里的一种特殊情况,叫做二元信号量

这个牌子就是信号量,描述了可用资源的个数

每次申请一个可用资源,计数器就-1(也就是P操作 ->acquire 申请

每次释放一个可用资源 计数器就+1 也就是V操作 ->release 释放

当信号量的计数为0 再次进行p操作,就会阻塞等待

锁就可以视为二元信号量.可用资源就一个,计数器的取值非0即1

4.CountDownLatch

终点线

countdown 给每个线程里面调用就表示到达终点

await 给等待线程去调用 所有任务都到达终点了.awit就阻塞返回 就表示任务完成

当所有的选手都冲过终点才认为是比赛结束

多线程下载

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch=new CountDownLatch(10);//表示有10个选手
        for (int i = 0; i < 10; i++) {
            Thread t =new Thread(()->{
                try {
                    Thread.sleep(3000);
                    System.out.println(Thread.currentThread().getName()+"已到达");
                    countDownLatch.countDown();//记录次数
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            t.start();
        }
        //当十个线程都执行完,await才停止阻塞
        countDownLatch.await();
        System.out.println("比赛结束");
    }

五.哈希表

HashMap本身是线程不安全的

1.HashTable->推荐

2.ConcurrentHashMap->不推荐

针对this加锁,只要有多个线程来访问HashTable,就会加锁

假设员工想请假,就得当面来申请,他好签字

由于公司里的人很多,很多人都要请假,这个时候大家都在老板门口排队,非常不方便

每个HashTable都只有一把锁

解决方法

ConcurrentHashMap

每个链表头加锁

1.面试问题-CconcurrentHashMap和HashTable的关系

1.ConcurrentHashTable只是减少了锁冲突,就让锁加到每个链表的头节点

2,ConcurrentHashMap只是针对写操作 读操作没加锁

3,ConcurrentHashMap广泛使用CAS,

4,ConcurrentHashMap针对扩容,巧妙的化整为零

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

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

相关文章

HT32合泰单片机开发环境搭建和配置教程

HT32合泰(Holtek)单片机开发环境搭建安装教程 前言 最近在准备合泰杯的比赛&#xff0c;在看合泰官方的PPT和数据手册学习&#xff0c;顺便做个合泰单片机的开发环境搭建教程。 合泰杯比赛发放的开发板是ESK32-30501&#xff0c;用的单片机是HT32F52352。 合泰杯官网地址&a…

【C++】vector的使用及其模拟实现

这里写目录标题一、vector的介绍及使用1. vector的介绍2. 构造函数3. 遍历方式4. 容量操作及空间增长问题5. 增删查改6. vector二维数组二、vector的模拟实现1. 构造函数2. 迭代器和基本接口3. reserve和resize4. push_back和pop_back5. insert和erase5. 迭代器失效问题5. 浅拷…

Java中的 this 和 super

1 this 关键字 1.1 this 访问本类属性 this 代表对当前对象的一个引用 所谓当前对象&#xff0c;指的是调用当前类中方法或属性的那个对象this只能在方法内部使用&#xff0c;表示对“调用方法的那个对象”的引用this.属性名&#xff0c;表示本对象自己的属性 当对象的属性和…

IntelliJ IDEA 编码设置

1.场景 适用于配置idea文件编码 2.配置 对已经存在的项目设置文件编码 可以设置全局的编码 以及 项目的编码 一般没啥特殊要求 都建议设置为 UTF-8 以及 配置项目的目录的单独编码 也建议UTF-8 idea可以单独设置properties的编码 也建议改为 UTF-8&#xff0c;其中有一个重点…

HCIP --- GRE和MGRE

VPN----虚拟私有网络&#xff1a;依靠ISP或者其他网络管理机构在公有网络基础上构建的专用的安全数据通信网络&#xff0c;只不过该网络是逻辑上的而非物理的。 虚拟&#xff1a;用户不再需要拥有实际的长途数据线路&#xff0c;而是使用公共网络资源建立的属于自己的私有网络…

[论文笔记]Transformer-XL: Attentive Language Models Beyond a Fixed-Length Context

引言 我们知道Transformer很好用&#xff0c;但它设定的最长长度是512。像一篇文章超过512个token是很容易的&#xff0c;那么我们在处理这种长文本的情况下也想利用Transformer的强大表达能力需要怎么做呢&#xff1f; 本文就带来一种处理长文本的Transformer变种——Transf…

SQS (Simple Queue Service)简介

mazon Simple Queue Service (SQS)是一种完全托管的消息队列服务&#xff0c;可以让你分离和扩展微服务、分布式系统和无服务应用程序。 在讲解SQS之前&#xff0c;首先让我们了解一下什么是消息队列。 消息队列 还是举一个电商的例子&#xff0c;一个用户在电商网站下单后付…

【LeetCode每日一题:[面试题 17.05] 字母与数字-前缀和+Hash表】

题目描述 给定一个放有字母和数字的数组&#xff0c;找到最长的子数组&#xff0c;且包含的字母和数字的个数相同。 返回该子数组&#xff0c;若存在多个最长子数组&#xff0c;返回左端点下标值最小的子数组。若不存在这样的数组&#xff0c;返回一个空数组。 示例 1: 输入…

LDGRB-01 3AFE61320954P0001

LDGRB-01 3AFE61320954P0001变频器的作用_变频器工作原理变频器是把工频电源&#xff08;50Hz或60Hz&#xff09;变换成各种频率的交流电源&#xff0c;以实现电机的变速运行的设备&#xff0c;其中控制电路完成对主电路的控制&#xff0c;整流电路将交流电变换成直流电&#x…

教育培训机构屡遭投诉?湖南中创教育给出三点建议

在中消协发布的《2021年校外教育培训领域消费者权益保护报告》中&#xff0c;受新冠疫情以及校外教育培训行业治理政策的冲击&#xff0c;我国校外教育培训领域消费维权舆情及消费者投诉呈上升趋势。2021年全国消协组织受理有关校外教育培训的投诉案件共80,528件&#xff0c;同…

探索N-gram模型:语言模型中的基础算法

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

Proteus8.15安装教程

1、解压Proteus8.15 安装包&#xff0c;然后双击进去&#xff0c;找到setup文件&#xff0c;右键&#xff0c;以管理员身份运行。 2、需要安装一些插件&#xff0c;点击“next”。把插件安装完成。 点击“finfish” 点击“install” 点击“Cancel” 3、如果没有上面步骤&…

零拷贝技术

1. 零拷贝技术 零拷贝就是一种避免 CPU 将数据从一块存储拷贝到另外一块存储的技术。针对操作系统中的设备驱动程序、文件系统以及网络协议堆栈而出现的各种零拷贝技术极大地提升了特定应用程序的性能&#xff0c;并且使得这些应用程序可以更加有效地利用系统资源。这种性能的…

latex使用笔记

在线表格转latex格式:https://tablesgenerator.com/ 在线公式转latex格式:https://latex.91maths.com/ 1、希腊字母 eg.σ 2、% 3、大小写罗马数字 大写罗马数字&#xff1a;\uppercase\expandafter{\romannumeral} 在romannumeral后加上相应的数字即可。 eg.Ⅱ \uppercas…

Python每日一练(20230311)

目录 1. 合并两个有序数组 2. 二叉树的右视图 3. 拼接最大数 &#x1f31f; 每日一练刷题专栏 C/C 每日一练 ​专栏 Python 每日一练 专栏 1. 合并两个有序数组 给你两个有序整数数组 nums1 和 nums2&#xff0c;请你将 nums2 合并到 nums1 中&#xff0c;使 nums1 成为…

SpringSecurity第一讲

目录 一、SpringSecurity01 1.2 什么是会话 1.2.1 基于session的认证 1.2.2 基于ToKen的认证 1.3 什么是授权 1.3.1 为什么要授权 1.3.2 SpringSecurity简介 1.4 SpringSecurity入门 1.4.1 pom文件 1.4.2 主启动类 1.4.3 创建控制层 1.4.4 启动项目进行测试 1.5 自…

工作三年,月薪不到20k,软件测试工程师,担心被应届生取代

工作了3年&#xff0c;一个月工资不到20K&#xff0c;担心被应届毕业生取代&#xff01; 互联网的快速发展伴随着员工适者生存的加速。几年是一条分界线。如果人们的能力和体力不够&#xff0c;他们就会被淘汰。生动的工作生活让许多人焦虑不安。 最近&#xff0c;一名来自211本…

Java分布式事务(五)

前言 随着互联网的快速发展&#xff0c;软件系统由原来的单体应用转变为分布式应用&#xff0c;下图描述了单体应用向微服务的演变。 文章目录&#x1f525;分布式事务处理-认识分布式事物&#x1f525;分布式架构的理论知识-CAP理论&#x1f525;分布式事务处理-分布式事务产…

查询校园网是否支持IPv6绕过校园网

方法一、连接校园网&#xff0c;登录认证网络可用后返回WIFI页面点击校园网WIFI的属性查看是否有IPV6地址 本地的IPV6地址不算哦 &#xff08;一般IPv6地址都是数字开头&#xff0c;fe80开头的都是本地IPv6地址是没用的&#xff09;方法二、连接校园网&#xff0c;登录认证网络…

《信号分析与处理》期末复习题库整理(题目+手写知识点+答案+期末知识点精细)

文章目录一、傅里叶变换、s域变换、z域变换&#xff08;待&#xff1a;整理一些常用以及方程变换&#xff09;傅里叶变换s域变换z域变换二、试卷一、选择题12345678910111213141516171819202122232425262728二、填空题123567891011121314151617三、计算题123456781011121314151…