Java并发控制 学习笔记1

一、并发控制的方法

1、悲观锁:常用的互斥锁都属于悲观锁,一个线程访问共享资源时其他线程不能访问。

2、乐观锁:允许同时访问共享数据,只有在提交时利用如版本号检查是否有冲突,应用github。

3、什么时候用乐观锁、什么时候用悲观锁?

写操作比较多的时候悲观锁,读操作多用乐观锁。再就是一个事务执行时间很长时用乐观锁,冲突很多时考虑悲观锁。

二、什么是自旋锁?

正常的锁当一个线程拿不到共享资源时,会把该线程阻塞,等共享资源释放后,再唤醒该阻塞线程并进行调度;

自旋锁当一个线程拿不到共享资源时,它就一直while循环来询问该资源释放了没有,会一直占用cpu资源。

适用情况:如果大多事务的执行时间很短,自旋锁空转一会就能拿到资源,就用自旋锁,这时如果采用阻塞/唤醒思路的话,调度的时间消耗会比较大。

三、代码实现:

例1(leetcode1114按序打印):

方案1(synchronized关键字):

        既可以实现自旋锁,也可以实现阻塞/唤醒思路,但要注意自旋锁时很容易死锁,所以synchronized包裹哪一部分代码考虑清楚,同时若出现“不可见”问题,考虑适用volatile关键字。

代码(自旋锁):

class Foo {

    private volatile Integer flag = 0;

    public Foo() {
        
    }

    public void first(Runnable printFirst) throws InterruptedException {
        
// 1、正常synchronized解决了“不可见问题”,
// 但因为这里flag!=0在synchronized代码块外边,
// 所以这里的flag用的是“线程存储空间中的值”,
// 不是主存中的最新值,所以使用volatile来定义flag变量;

// 2、另外synchronized(this)为什么不是synchronized(flag),
// 因为Integer flag是引用类型,改变flag的值,flag指向的存储空间就变了,
// 作为共享资源的变量存储空间是一直不能变的。
        while (flag !=0) {} 
        synchronized(this) {
            printFirst.run();
            flag = 1;
        }
        
    }

    public void second(Runnable printSecond) throws InterruptedException {
        
            
        while (flag != 1) {}
        synchronized(this) {
            System.out.println(".." + flag);
            printSecond.run();
            flag = 2;
        }
        
    }

    public void third(Runnable printThird) throws InterruptedException {
        
        while (flag != 2);
        synchronized(this) {
            System.out.println(flag);
            flag = 0;
            printThird.run();
        }

    }
}


///
synchronized少包裹一些代码也行,如下:

class Foo {

    private volatile Integer flag = 0;

    public Foo() {
        
    }

    public void first(Runnable printFirst) throws InterruptedException {
        
        
        while (flag !=0) {}
        
        printFirst.run();
        synchronized(this) {
            flag = 1;
        }
        
    }

    public void second(Runnable printSecond) throws InterruptedException {
        
            
        while (flag != 1) {}

        printSecond.run();
        synchronized(this) {
            flag = 2;
        }
        
    }

    public void third(Runnable printThird) throws InterruptedException {
        
        while (flag != 2);
        printThird.run();
        synchronized(this) {
            flag = 0;
        }

    }
}

代码(阻塞/唤醒思路):

class Foo {

    private Integer flag = 0;

    public Foo() {
        
    }

    public void first(Runnable printFirst) throws InterruptedException {
        // 可以用this,也可以另外定义一个一定不会被修改的Object,
        // 但不能用flag,原因如上代码。
        synchronized(this) {
            while (flag !=0) {this.wait();}
            printFirst.run();
            flag = 1;
            this.notifyAll();
        }
        
    }

    public void second(Runnable printSecond) throws InterruptedException {
        synchronized(this) {
            
            while (flag != 1) {this.wait();}
            printSecond.run();
            flag = 2;
            this.notifyAll();
        }
        
    }

    public void third(Runnable printThird) throws InterruptedException {
        synchronized(this) {
            while (flag != 2) this.wait();
            flag = 0;
            printThird.run();
            this.notifyAll();
        }

    }
}

方案2(Lock类):和synchronized关键字差不多,只不过是一个封装好的类,还是得借助volatile关键字实现解决可见性,下面代码是自旋锁思路,也可以用条件锁Condition类实现阻塞思路,如文章最后的链接中的方法(synchronized配合wait等方法  == Lock配合Condition,只不过前者更底层);

class Foo {

    private volatile Integer flag;
    private Lock lock = new ReentrantLock();

    public Foo() {
        flag = 0;
    }

    public void first(Runnable printFirst) throws InterruptedException {
        
        while (flag != 0) {}
        lock.lock();
        printFirst.run();
        flag = 1;
        lock.unlock();
    }

    public void second(Runnable printSecond) throws InterruptedException {
        while (flag != 1);   
        lock.lock();     
        printSecond.run();
        flag = 2;
        lock.unlock();
    }

    public void third(Runnable printThird) throws InterruptedException {
        while (flag != 2);
        lock.lock();
        printThird.run();
        flag = 0;
        lock.unlock();
    }
}

方案3(原子类AtomicInteger类):

也是既可以实现自旋锁,也可以实现阻塞唤醒,AtomicInteger不用=、!=、+等运算符,要调用get()方法、set()方法、incrementAndGet()等方法。

自旋锁代码:

class Foo {
    
    private AtomicInteger flag = new AtomicInteger(0);

    public Foo() {
        System.out.println(flag);
    }

    public void first(Runnable printFirst) throws InterruptedException {
        
        while (flag.get() != 0);
        printFirst.run();
        flag.set(1);
    }

    public void second(Runnable printSecond) throws InterruptedException {
        
        while (flag.get() != 1);
        printSecond.run();
        flag.set(2);
    }

    public void third(Runnable printThird) throws InterruptedException {
        
        while (flag.get() != 2);
        printThird.run();
        flag.set(0);
    }
}

阻塞/唤醒思路代码:

使用xx.wait、xx.notifyALL函数时,xx一定得对于所有线程可见。xx可以是另外定义的一个量,并配合synchronized关键字实现对所有线程可见,或者不用synchronized用volatile修饰一下也可以。

对于AtomicInteger类 阻塞不好实现,wait、notifyAll还是配合synchronized关键字用。

方案4(信号量、计数器、阻塞队列等,这些方面实现阻塞/唤醒思路,同时因为这些工具类都是线程安全的,都能满足“可见性”,所以只要这些工具类能有类似AtomicInteger类get/set方法的方法,那也能实现自旋锁,不过我还没试过...),下面链接都属阻塞/唤醒思路的:

链接:力扣icon-default.png?t=N2N8https://leetcode.cn/problems/print-in-order/solutions/488685/si-chong-bu-tong-de-shi-xian-fang-shi-zong-jie-by-/

end...

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

携程平台增长部总经理王绩强:原生互联网企业正在经历一场数字升级丨数据猿专访...

‍数据智能产业创新服务媒体——聚焦数智 改变商业以大数据和人工智能为核心,众多新兴技术开始赋能数字营销。于是,智能营销已然从工具化走向了业务化。如今,数字化营销已经成为了企业数字化转型中的重要一环。相较于传统营销逻辑&#xff0…

新版新款影视直播粉红色UI的麻豆CMS源码/带教程/支付已接

基于苹果CMS v10影视系统框架开发的前端模板,带会员中心,可设置试看付费观看等功能。 经过测试及修复,这套源码功能还是很强大的,可以设置一键采集,并且支付我们给他接到了易支付,拓展性强,基本…

【压测】通过Jemeter进行压力测试(超详细)

文章目录背景一、前言二、关于JMeter三、准备工作四、创建测试4.1、创建线程组4.2、配置元件4.3、构造HTTP请求4.4、添加HTTP请求头4.5、添加断言4.6、添加察看结果树4.7、添加Summary Report4.8、测试计划创建完成五、执行测试计划总结背景 通过SpringCloudGateway整合Nacos进…

如何下载ChatGPT-ChatGPT如何写作

CHATGPT能否改一下文章 ChatGPT 作为一种自然语言处理技术,生成的文章可能存在表达不够准确或文风不符合要求等问题。在这种情况下,可以使用编辑和修改来改变输出的文章,使其符合特定的要求和期望。 具体来说,可以采用以下步骤对…

超越竞争对手:利用Facebook A/B测试优化广告效果!

随着社交媒体广告的普及,Facebook已经成为了许多公司推广业务的重要平台。但是,在Facebook上发布广告并不意味着成功,这也让许多公司开始关注如何优化广告效果。 在这篇文章中,我将介绍如何使用A/B测试来优化Facebook广告&#x…

纳米软件关于集成电路测试的分类介绍

集成电路测试可以按照测试目的、测试内容、按照器件开发和制造阶段分类。参照需要达到的测试目的对集成电路测试进行分类,可以分为:验证测试、制造测试、老化测试、入厂测试等。按照测试所涉及内容,集成电路测试可分为:参数测试、功能测试、结构测试等。…

2023/4/4总结

题解: Problem ​​​​​​ A - Codeforces 1.这道题目我们需要判断。 2.如果是奇数,亦或出来的总值不为0,那么每一个数字再去亦或任何一个数字,都不会为0。 3.如果是偶数并且亦或总值为0,那么我们亦或的总值不满…

记录重启csdn

有太多收藏的链接落灰了,在此重启~ 1、社会 https://mp.weixin.qq.com/s/Uq0koAbMUk8OFZg2nCg_fg https://mp.weixin.qq.com/s/yCtLdEWSKVVAKhvLHxjeig https://zhuanlan.zhihu.com/p/569162335?utm_mediumsocial&utm_oi938179755602853888&ut…

使用npm包,全局共享数据,分包

使用 npm 包 1、Vant Weapp 1.1、什么是 Vant Weapp Vant Weapp 是有赞前端团队开源的一套小程序 UI 组件库,助力开发者快速搭建小程序应用。它所使用的是MIT 开源许可协议,对商业使用比较友好。 官方文档地址 https://youzan.github.io/vant-weapp …

Huggingface微调BART的代码示例:WMT16数据集训练新的标记进行翻译

BART模型是用来预训练seq-to-seq模型的降噪自动编码器(autoencoder)。它是一个序列到序列的模型,具有对损坏文本的双向编码器和一个从左到右的自回归解码器,所以它可以完美的执行翻译任务。 如果你想在翻译任务上测试一个新的体系…

游戏运营专员的职责有哪些?提高游戏收入的关键是什么?

游戏运营是将一款游戏平台推入市场,通过对平台的运作,使用户从接触、认识、再到了解实际线上的一种操作、最终成为这款游戏平台的忠实玩家的这一过程。同时通过一系列的营销手段达到提高线上人数,刺激消费增长利润的目的。 游戏运营专员的职…

Go 连接池的设计与实现

为什么需要连接池 如果不用连接池,而是每次请求都创建一个连接是比较昂贵的,因此需要完成3次tcp握手 同时在高并发场景下,由于没有连接池的最大连接数限制,可以创建无数个连接,耗尽文件描述符 连接池就是为了复用这…

高效的实现金蝶云星空ERP与自研MES系统数据集成

一、项目背景 随着企业数字化转型的不断深入,数据集成变得愈发重要。金蝶云星空ERP与自研MES系统之间的数据集成是企业提高管理效率、降低运营成本的关键。为了实现这一目标,企业选择了轻易云数据集成平台进行数据集成。 二、项目实施过程 低耦合、高内…

二叉树的前序遍历(力扣144)

目录 题目描述: 解法一:递归法 解法二:迭代法 解法三:Morris 遍历 二叉树的前序遍历 题目描述: 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。 示例 1: 输入:root […

Unity反编译:AssetStudio资源浏览器及代码查看器

前言 假如你手上有Unity发布出来的exe文件、apk文件或者webGL文件,但就是没有工程源文件,那么,如何从这些文件里面一窥究竟呢?这就需要资源提取工具以及代码反编译工具! 本文所涉软件【文中附有下载链接】&#xff1…

【接口测试工具】Eolink Apikit 快速入门教程

Eolink Apikit 下载安装【官方版】:https://www.eolink.com/apikit 发起 API 测试 进入 API 文档详情页,点击上方 测试 标签,进入 API 测试页,系统会根据 API 文档自动生成测试界面并且填充测试数据。 填写请求参数 首先填写好请…

【创作赢红包】python学习——【第七弹】

前言 上一篇文章 python学习——【第六弹】中介绍了 python中的字典操作,这篇文章接着学习python中的可变序列 集合 集合 1: 集合是python语言提供的内置数据结构,具有无序性(集合中的元素无法通过索引下标访问,并且…

UDP协议详解

目录 UDP协议报文结构 端口号 报文长度 校验和 生成校验和的算法 MD5的特点 UDP协议报文结构 UDP会把载荷数据(也就是通过 UDP socekt,send方法拿来的数据基础上,再前面拼装(相当于字符串拼接此处是二进制的)上几个字节的报头 UDP报头里包含了一些特定的属性,这些属性携带…

阿里云linux云服务器 安装指定版本node.js

我们在实例管理中找到自己的服务器 然后点击右侧的 远程连接 接着点击理解登录 进入命令窗口 我们在这上面输入 curl -h阿里云的服务器都还是最好会有 curl的 然后 我们输入 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash下把nvm下下…

量化注意事项和模型设计思想

量化的注意事项 1、量化检测器时,尽量不要对Detect Head进行量化,一旦进行量化可能会引起比较大的量化误差; 2、量化模型时,模型的First&Second Layer也尽可能不进行量化(精度损失具有随机性)&#xf…
最新文章