Java线程安全问题

news2024/11/25 6:28:16

1、什么是线程安全问题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、用程序模拟线程安全问题

在这里插入图片描述
代码说明:

  1. Account代表账户类
  2. DrawThread代表线程类
  3. ThreadTest运行线程类

Account类:

package ThreadSave;

public class Account {
    private double money;  //余额
    private String cardId; //卡号

    public Account() {
    }

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

    public double getMoney() {
        return money;
    }

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

    public String getCardId() {
        return cardId;
    }

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

    //取钱操作
    public void drawMoney(double money) {
        //先搞清楚谁在取钱
        String name = Thread.currentThread().getName();
        //开始进入取钱逻辑
        if (this.money>=money){
            System.out.println(name+"来取钱"+money+"成功!");
            this.money -= money;
            System.out.println(name+"来取钱后余额为:"+ this.money);

        }else {
            System.out.println(name+"来取钱---余额不足");
        }
    }
}

DrawThread类:

package ThreadSave;

public class DrawThread extends Thread{

    private Account acc;

    public DrawThread(Account acc,String name){
        super(name);
        this.acc = acc;
    }


    @Override
    public void run() {
        //取钱
        acc.drawMoney(100000);
    }




}

ThreadTest类:

package ThreadSave;

//目标:模拟线程安全问题
public class ThreadTest {
    public static void main(String[] args) {

        //1、创建一个账户对象,代表两个人的共享账号
        Account acc = new Account(100000,"ICBC-110");

        //2、创建2个线程,分别代表小明,小红,再去同一个账户对象取10万元
        new DrawThread(acc,"小明").start(); //代表小明
        new DrawThread(acc,"小红").start(); //代表小红
    }
}

运行结果:
在这里插入图片描述

3、线程同步

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1、同步代码块

在这里插入图片描述
在共享资源上加锁,我们上面案例的共享资源在Account类中,因此我们需要对Account中的代码进行加锁,修改后的代码:
加锁快捷键:选中取钱部分代码----》Ctrl+Alt+T选择synchronized

package ThreadSave;

public class Account {
    private double money;  //余额
    private String cardId; //卡号

    public Account() {
    }

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

    public double getMoney() {
        return money;
    }

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

    public String getCardId() {
        return cardId;
    }

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

    //取钱操作
    public void drawMoney(double money) {
        //先搞清楚谁在取钱
        String name = Thread.currentThread().getName();
        //1、判断余额是否足够
        //-------------------------------------------------------------------------------------
        //加锁
        synchronized ("海梦") {
            //开始进入取钱逻辑
            if (this.money>=money){
                System.out.println(name+"来取钱"+money+"成功!");
                this.money -= money;
                System.out.println(name+"来取钱后余额为:"+ this.money);

            }else {
                System.out.println(name+"来取钱---余额不足");
            }
        }
    }
}

运行结果:
在这里插入图片描述
注意事项:在上面的锁中,我们随意使用了一个 "海梦"来完成,这样会产生一些问题,因为它可锁住任何线程进行访问。
我们需要把 “海梦” 改为 this,这样就没有问题了。

如果还静态锁的话,我们应该使用class作为锁,示例代码:

//静态方法加锁
    public static void test(){
        synchronized (Account.class){
            
        }
    }

在这里插入图片描述

2、同步方法

在这里插入图片描述

对方法加锁:
取钱操作
public synchronized void drawMoney(double money)
具体代码:

package ThreadSave;

public class Account {
    private double money;  //余额
    private String cardId; //卡号

    public Account() {
    }

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

    public double getMoney() {
        return money;
    }

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

    public String getCardId() {
        return cardId;
    }

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

    //取钱操作
    public synchronized void drawMoney(double money) {
        //先搞清楚谁在取钱
        String name = Thread.currentThread().getName();
        //1、判断余额是否足够
        //this正好代表共享资源
            //开始进入取钱逻辑
            if (this.money>=money){
                System.out.println(name+"来取钱"+money+"成功!");
                this.money -= money;
                System.out.println(name+"来取钱后余额为:"+ this.money);

            }else {
                System.out.println(name+"来取钱---余额不足");
            }
    }
}

在这里插入图片描述

3、Lock锁

在这里插入图片描述
在Account类中创建一个锁对象
然后在特定的位置(共享资源位置)加锁
执行完后再解锁
相关代码:

package ThreadSave;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Account {
    private double money;  //余额
    private String cardId; //卡号

    //创建一个锁对象
    private final Lock lk = new ReentrantLock();

    public Account() {
    }

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

    public double getMoney() {
        return money;
    }

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

    public String getCardId() {
        return cardId;
    }

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

    //取钱操作
    public void drawMoney(double money) {
        //先搞清楚谁在取钱
        String name = Thread.currentThread().getName();
        //加锁
        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+"来取钱---余额不足");
            }
        //解锁
        lk.unlock();
    }
}

注意事项:如果在lk.lock()和lk.unlock()中间出现bug,那么就会解锁失败,因此我们应该把中间的代码放在try-catch-finally中
示例代码:

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();
        }

在这里插入图片描述

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

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

相关文章

基于天牛须优化的BP神经网络(分类应用) - 附代码

基于天牛须优化的BP神经网络(分类应用) - 附代码 文章目录 基于天牛须优化的BP神经网络(分类应用) - 附代码1.鸢尾花iris数据介绍2.数据集整理3.天牛须优化BP神经网络3.1 BP神经网络参数设置3.2 天牛须算法应用 4.测试结果&#x…

使用图像处理跟踪瞳孔(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

比较和同步数据库架构和数据:MssqlMerge Pro Crack

比较和同步数据库架构和数据 适用于Oracle、MySQL 和 MariaDB、SQL Server、PostgreSQL、SQLite、MS Access和跨 DBMS 场景 业界领先的文本比较工具中常用的两面板 UI 快速过滤器显示所有/新/更改/新更改 合并两个方向的更改 轻量级:跨 DBMS 工具小于 20 MB&#xf…

【Java学习之道】Swing框架与组件介绍

引言 在本篇文章中,我们将重点介绍Swing框架及其组件。Swing是一个用于构建图形用户界面的Java库,它提供了丰富的组件和布局管理器,可以帮助你轻松地创建出漂亮、功能强大的界面。无论你是刚开始学习Java还是已经有一些经验,我相…

VR太空舱体验馆VR神舟返回舱VR虚拟现实科技科普乐园

VR航天航空设备,寓教于乐 VR科技正成为航天航空领域的新宠。作为一种沉浸式的数字技术,VR(Virtual Reality,虚拟现实)能够为用户创造出逼真的虚拟环境,让人们仿佛身临其境。借助VR技术,我们可以带领学生和游客深入了解…

基于秃鹰优化的BP神经网络(分类应用) - 附代码

基于秃鹰优化的BP神经网络(分类应用) - 附代码 文章目录 基于秃鹰优化的BP神经网络(分类应用) - 附代码1.鸢尾花iris数据介绍2.数据集整理3.秃鹰优化BP神经网络3.1 BP神经网络参数设置3.2 秃鹰算法应用 4.测试结果:5.M…

python 对图片增加边框,logo贴图,获取图片exif参数,填写图片文本内容

完整代码 # 找到个可以下载免费字体的网站https://font.chi删除我naz.com/mi删除我anfei.html from PIL import Image, ImageDraw, ImageFont import exifreaddef photo_exif(image_path):f open(image_path, rb)tags exifread.process_file(f)# 打印所有照片信息&#xff0…

Redis Windows版下载,带安装包

1、直接下载解压缩至任意全英文路径 打开后会看到都有这个目录 2、如何启动redis? 双击redis-server.exe 即可启动redis服务 注:若想保持redis处于开启状态,不要关闭启动后的窗口 关闭窗口后,一般情况下redis服务会默认随之关闭…

【物联网+JAVA 】智慧工地源码

一、什么是智慧工地? 工地本身不拥有智慧,工地的运作是依赖于人的智慧。工地信息化技术,能够减少对人的依赖,使工地拥有智慧。 智慧工地,就是立足于“智慧城市”和“互联网”,采用云计算、大数据和物联网…

礼品小程序商城的作用是什么

礼品总是在不同场景中出现,拓展度高,线上线下经营商家众多,而在实际经营中,礼品企业经营痛点也不少。 互联网电商时代,人们更依赖于线上购物,商家可以通过线上经营卖货及赋能客户消费。 通过【雨科】平台搭…

openGauss学习笔记-99 openGauss 数据库管理-管理数据库安全-客户端接入认证之配置文件参考

文章目录 openGauss学习笔记-99 openGauss 数据库管理-管理数据库安全-客户端接入认证之配置文件参考99.1 参数说明99.2 认证方式 openGauss学习笔记-99 openGauss 数据库管理-管理数据库安全-客户端接入认证之配置文件参考 99.1 参数说明 表 1 参数说明 参数名称描述取值范…

传感器信息系统中的节能收集研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

图形界面四则运算计算器(Python+PyQt5)

(1) 导入所需的库和模块。 (2) 创建一个名为Calculator的类,继承自QMainWindow。 (3) 在Calculator类的__init__方法中,调用initUI方法初始化界面。 (4) 在initUI方法中,设置窗口标题和大小,创建显示结果的文本框,并调…

深度学习开发流程

1.全局流程 2.训练过程 损失函数:用来度量深度学习模型的预测值f(x)与真实标签值Y的差异程度的运算函数,损失函数越小,模型型训练的效果越好。 2.1 深度学习训练主要训练步骤: 确定模型将模型加在到cpu或者gpu中确定训练数据确定优化器和超…

接口测试入门:深入理解接口测试!

很多人会谈论接口测试。到底什么是接口测试?如何进行接口测试?这篇文章会帮到你。 一、前端和后端 在谈论接口测试之前,让我们先明确前端和后端这两个概念。 前端是我们在网页或移动应用程序中看到的页面,它由 HTML 和 CSS 编写…

【重拾C语言】十二、C语言程序开发(自顶向下、逐步求精;结构化程序设计原则;程序风格)

目录 前言 12.1 求玉米单产——自顶向下、逐步求精 12.1.1 自顶向下、逐步求精 12.1.2 求玉米单产 12.2 结构化程序设计原则 12.2.1 顺序 12.2.2 选择 12.2.3 循环 12.2.4 模块化 12.3 程序风格 12.3.1 程序风格 12.3.2 行文格式、标识符 12.3.3 注释及其它 前言…

露营装备经营商城小程序搭建

近几年露营人群逐渐增加,相应的装备商也多了起来,各种分类商品在一定程度上销量都非常不错,然而传统线下门店经营方面,面对的痛点也不少。 通过【雨科】平台搭建露营装备商城,让客户多场景平台随时购物,多流…

【论文解读】人工智能时代的科学发现

一、简要介绍 人工智能(AI)正越来越多地融入到科学发现中,以增强和加速研究,帮助科学家产生假设、设计实验、收集和解释大型数据集,并获得仅使用传统的科学方法可能无法获得的见解。在这里,论文研究了过去十…

SecureCRT 自动测试脚本的使用方法

脚本示例(get_batteryifo_interval_2s.vbs): Sub Main Do While(1)crt.Screen.Send "pm_client batteryinfo" & chr(13)crt.Sleep 2000 Loop End Sub 1. 解压 SecureCRT 压缩包(网上下载)&#xff1b…

渗透波菜网站

免责声明 本文发布的工具和脚本,仅用作测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。如果任何单位或个人认为该项目的脚本可能涉嫌侵犯其权利&#xff0c…