[进阶]Java:多线程:线程同步

news2024/11/24 17:22:58

线程同步

  • 解决线程安全问题的方案。

线程同步的思想

  • 让多个线程实现先后一次访问共享资源,这样就解决了安全问题。

线程同步的常见方案:

  • 加锁:每次只允许一个线程加锁,加锁后才能进入访问,访问完毕后自动解锁,然后其他线程才能再加锁进来。

同步代码块

  • 作用:把访问共享资源的核心代码给上锁,以此保证线程安全。
  • 原理:每次只允许一个线程加锁后进入,执行完毕后自动解锁,其他线程才可以进来执行。

同步锁的注意事项

  • 对于当前同时执行的线程来说,同步锁必须是同一把(同一个对象),否则会出bug。

代码演示如下(完整代码请查看上篇文章,改动的只有在账户类有改动):

public class Account {
    private String cardId;
    private double money;

    public Account() {
    }

    public Account(String cardId, double money) {
        this.cardId = cardId;
        this.money = money;
    }

    // 静态方法用类名.class作为锁
    public static void test(){
        synchronized (Account.class){

        }
    }


    //小明 小红同时过来的
    public void drawMoney(double money){
        // 先搞清楚是谁来取钱
        String name = Thread.currentThread().getName();
        //1.判断余额是否足够
        // this正好代表共享资源
        synchronized (this) {
            if (this.money >= money){
                System.out.println(name + "来取钱" + money + "成功~");
                this.money -= money; // 更新余额
                System.out.println(name + "来取钱后,余额剩余:" + this.money);
            }else {
                System.out.println(name + "来取钱,余额不足~");
            }
        }
    }

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
}

锁对象随便选择一个唯一的对象好不好呢?

  • 不好,会影响其他无关线程的执行。

锁对象的使用范围

  • 建议使用共享资源作为对象锁,对于实例方法建议使用this作为锁对象。
  • 对于静态方法建议使用字节码(类名.class)对象作为锁对象。

同步方法

  • 作用:把访问共享资源的核心方法给上锁,一次保证线程安全。
  • 原理:每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行。

代码演示如下:

public class Account {
    private String cardId;
    private double money;

    public Account() {
    }

    public Account(String cardId, double money) {
        this.cardId = cardId;
        this.money = money;
    }

    //小明 小红同时过来的
    public synchronized void drawMoney(double money){
        // 先搞清楚是谁来取钱
        String name = Thread.currentThread().getName();
        //1.判断余额是否足够
        if (this.money >= money){
            System.out.println(name + "来取钱" + money + "成功~");
            this.money -= money; // 更新余额
            System.out.println(name + "来取钱后,余额剩余:" + this.money);
        }else {
            System.out.println(name + "来取钱,余额不足~");
        }
    }

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
}

同步方法底层原理:

  • 同步方法其实底层也是隐式锁对象的,只是锁的范围是整个方法代码。
  • 如果方法是实例方法:同步方法默认用this作为的锁对象。
  • 如果方法是静态方法:同步方法默认用类名.class作为锁对象。

问:是同步代码块好还是同步方法好一点?

  • 范围上:同步代码块锁的范围更小,同步方法锁的范围更大。
  • 可读性:同步方法更好。

Lock锁

  • Lock锁是DK5开始提供的一个新的锁定操作,通过它可以创建出锁对象进行加锁和解锁,更灵活、更方便、更强大。
  • Lock是接口,不能直接实例化,可以采用它的实现类ReentrantLock来构建Lock锁对象。

 

代码演示如下:

public class Account {
    private String cardId;
    private double money;
    // 创建了一个锁对象
    private final Lock lk = new ReentrantLock();

    public Account() {
    }

    public Account(String cardId, double money) {
        this.cardId = cardId;
        this.money = money;
    }

    //小明 小红同时过来的
    public void drawMoney(double money){
        // 先搞清楚是谁来取钱
        String name = Thread.currentThread().getName();
        try {
            lk.lock(); // 加锁
            //1.判断余额是否足够
            if (this.money >= money){
                System.out.println(name + "来取钱" + money + "成功~");
                this.money -= money; // 更新余额
                System.out.println(name + "来取钱后,余额剩余:" + this.money);
            }else {
                System.out.println(name + "来取钱,余额不足~");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lk.unlock(); // 解锁
        }
    }

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
}

Lock的常用方法

 

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

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

相关文章

css 使用杂记

水平居中 条件:必须有宽度,不能无限宽 行内元素:通过设置父元素text-align:center块元素:要设置宽度,然后 左右margin值为“auto” 垂直居中 条件:父元素必须有高度,不能无限高 行内元素&#…

【Solr】体验极速安装solr

目录 前言 安装下载- 方式一:官网下载- 方式二:仓库下载 启动方式 快速使用 前言 solr是基于java开发的,所以solr需要用到jdk环境,并且solr需要在tomcat容器中才能运行,所以需要提前配置好jdk和tomcat环境。 安装下载 需要注意的是&#…

【vue+el-transfer】穿梭框实现及遇到的bug,已解决

昨晚加班写的穿梭框组件,一边写一边遇到bug,果然只有bug才会让你印象更深刻,更值得记录 封装成组件FreezeTransfer 效果如下: 主要参考了官网上可搜索的这个示例 先说遇到的bug,然后贴完整的代码 1、el-transfer数据…

layui下select下拉框不显示或没有效果

layui下select下拉框不显示或没有效果 弹层layer选择框没有样式_不可点击_渲染失效的解决办法 一、必须给表单体系所在的父元素加上 class"layui-form" 在一个容器中设定 class"layui-form" 来标识一个表单元素块,如果你不想用 form&#xf…

java 高校学生信息管理系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 JSP 高校学生信息管理系统 是一套完善的系统源码,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,以及相应配套的设计文档,系统主要采用B/S模式开发 。 研究的基本内容是基于Web的学生信息…

2023 最新版网络安全保姆级指南,手把手带你从零基础进阶渗透攻防工程师

一份网络攻防渗透测试的学习路线,不藏私了! 2023最新500G《黑客&网络安全入门&进阶学习资源包》 1、学习编程语言(phpmysqljshtml) 原因:phpmysql 可以帮助你快速的理解 B/S 架构是怎样运行的,只有理解了他的运行原理才…

《机器学习公式推导与代码实现》chapter12-XGBoost

《机器学习公式推导与代码实现》学习笔记,记录一下自己的学习过程,详细的内容请大家购买作者的书籍查阅。 XGBoost 从算法精度、速度和泛化能力等性能指标来看GBDT,仍然有较大的优化空间。XGBoost是一种基于GBDT的顶级梯度提升模型。相较于…

提炼关键词是一种能力

提炼关键词,是一种能力 交流或写文字,都要提炼关键词 趣讲大白话:抓重点 【趣讲信息科技202期】 **************************** 大脑的信息通过关键词调取 语言的传达,通过关键词传递关键信息 搜索要输入关键词 人工智能也要提示关…

tensorRT 模型部署

讲解: 模型经过训练之后终端部署之前都会有一个模型转换的过程,英伟达也不例外, 模型转换的过程其实是一个模型优化与加速的过程,里面包含着引擎对模型的一系列操作, 比如说layer 级的融合,权重的量化、图层…

PMP考试中多少分算通过?

PMP考试成绩一般是在考完后 6-8 周开始出成绩,像之前318的PMP考试,5月8号晚上已经开始出成绩了,还没出来的也会陆续出来。 【如何查询成绩】 1、输入网址(PMI官网,不知道网址的私戳),点击 Log …

消息中间件中常见问题

如何保证消息不丢失 MQ的用途 异步发送(验证码,短信,邮件)MySQL,ES,Redis之间的数据同步分布式事务削峰填谷 消息可能丢失的环境 消息在产生端时候生产端挂掉,消息未到达交换机&#xff0c…

【新车评分】降价三万,排名第一的蔚来ES7更能打了?

去年6月,蔚来上市了该品牌第四款SUV车型——ES7,共分为两个版本标准版和首发版,发售价分别为46.8万和54.8万元。 不过近期蔚来以砍掉部分车主权益,换来了全系车型3万元的降价,ES7的起售价也来到了43.8万元和51.8万元。…

【Python 随练】利用递归方法求 5!

题目 利用递归方法求 5!。 简介 在本篇博客中,我们将使用递归方法解决一个数学问题:计算一个数的阶乘。阶乘是指将从1到某个正整数n的所有整数相乘,通常表示为n!。我们将介绍递归的概念,并给出一个完整的代码示例来计算给定数的…

P-Tuning v2: 与微调性能相等的提示性优化

原文:P-Tuning v2: Prompt Tuning Can Be Comparable to Fine-tuning Universally Across Scales and Tasks 作者: Xiao Liu1,2 , Kaixuan Ji1 代码: https://github.com/THUDM/P-tuning-v2 一、简介 二、准备工作 ---- 2.1 NLU的任务 ---- 2.2 提示优化 三、P-Tu…

什么是云原生?

目录 1.简介2.云元素的四要素 1.简介 云原生:是一种构建和运行应用程序的方法,是一套技术体系和方法论。云原生(CloudNative)是一个组合词,Cloud Native: Cloud 表示应用程序位于云中,而不是…

基于OpenMV 循迹小车 + WIFI无线图传

文章目录 一、工程环境二、OpenMV1. 色块选定2. 色块识别3. 串口通信4. WiFi无线图传5. 代码汇总 三、MSP430四、视频演示 一、工程环境 1. 软件 OpenMV IDECode Composer StudioMicrosoft Edge 2. 硬件 MSP430F5529OpenMV4 H7及其 WiFi拓展板视觉云台旋转编码器、oled显示…

国际原油期货怎么开户?国际原油期货开户流程是什么?

随着国际原油期货交易的大众化,国际原油期货交易的入市门槛也在逐渐降低,使越来越多的国际原油期货交易爱好者能够参与到这个交易市场中。很多朋友可能对国际原油期货开户有很多的疑问,是不是很繁琐?需不需要很多的证明文件&#…

论文解读 | 皮质电图系统与软机器人致动器的完美结合

原创 | 文 BFT机器人 01 研究内容 主要研究内容是关于一种电皮层图谱系统的部署,该系统使用软体机器人致动器。论文详细介绍了该系统的制造和实验方法,并提供了相关的图表和参考文献。该系统的设计旨在提高电皮层图谱系统的灵活性和可植入性&#xff0c…

vite+vue3+cesium环境搭建

1.创建一个Vite项目 npm create vitelatest 2.安装cesium插件:vite-plugin-cesium npm i cesium vite-plugin-cesium vite -D 3、配置vite.config.js import cesium from vite-plugin-cesium; export default defineConfig({ plugins: [vue(),cesium()] }) 4、清空…

软件测试技能,JMeter压力测试教程(二)

目录 前言 一、案例场景 二、登录请求 三、Json 提取器 四、关联请求 五、遇到的坑 前言 现在很多接口的登录是返回一个json数据,token值在返回的json里面,在jmeter里面也可以直接提取json里面的值 上一个接口返回的token作为下个接口的入参 一、…