解决线程不安全问题的几种方式

news2024/9/21 0:30:53

线程不安全问题

日常生活中我们会经常碰到在不同的平台上买各种票的问题,例如在App、线下售票窗口等购买火车票、电影票。这里面就存在着线程安全的问题,因为当多个线程访问同一个资源时,会导致数据出错,例如甲和乙两人同时看中了一张票,甲先点击购买,此时线程直接转到乙去执行,乙点击购买,并锁定票,但甲还不知道此时就会发生数据错误。
在这里插入图片描述
为了避免发生这样的错误,我们通过两种方式来解决线程不安全的问题。

使用同步代码块

  1. 格式:
synchronized(任意对象){
      线程可能出现不安全的代码
}
  1. 任意对象:就是我们的锁对象

  2. 执行: 一个线程拿到锁之后,会进入到同步代码块中执行,在此期间,其他线程拿不到锁,就进不去同步代码块,需要在同步代码块外面等待排队。等着执行的线程执行完毕,出了同步代码块,相当于释放锁了,等待的线程才能抢到锁,才能进入到同步代码块中执行。

public class MyTicket implements Runnable{
    int ticket = 100;//定义100张票
    Object obj = new Object();//任意new一个对象
    @Override
    public void run() {
        while(true){
            synchronized (obj){
                if (ticket>0){
                    System.out.println(Thread.currentThread().getName()+"买了第"+ticket+"张票");
                    ticket--;
                }
            }
        }
    }
}
public class Test {
    public static void main(String[] args) {
        MyTicket myTicket = new MyTicket();
        Thread t1 = new Thread(myTicket, "张三");
        Thread t2 = new Thread(myTicket, "李四");
        t1.start();
        t2.start();
    }
}

没有再出现抢票的情况。
在这里插入图片描述

使用同步方法

同步方法有两类,一种是非静态的,一种是静态的。

非静态同步方法

格式:

  修饰符 synchronized 返回值类型 方法名(参数){
      方法体
      return 结果
  }

可以通过同步代码块的方式了解到默认锁是this

public class MyTicket implements Runnable{
    int ticket = 100;//定义100张票
    @Override
    public void run() {
        while(true){
           method01();
           method02()
        }
    }
   	public synchronized void method(){
        if (ticket>0){
            System.out.println(Thread.currentThread().getName()+"买了第"+ticket+"张票");
            ticket--;
        }
    }
    public void method02(){
       synchronized(this){
           System.out.println(this+"..........");
           if (ticket>0){
               System.out.println(Thread.currentThread().getName()+"买了第"+ticket+"张票");
               ticket--;
           }
       }
   }
}

静态同步方法

格式:

修饰符 static synchronized 返回值类型 方法名(参数){
      方法体
      return 结果
  }

可以通过同步代码块的方式了解到默认锁是class对象

public class MyTicket implements Runnable{
    static int ticket = 100;//定义100张票
    @Override
    public void run() {
           	method01();
           	method02();
        }
    }

    public static synchronized void method01(){
        if (ticket>0){
            System.out.println(Thread.currentThread().getName()+"买了第"+ticket+"张票");
            ticket--;
        }
    }
    public static void method02(){
        synchronized(MyTicket.class){
            if (ticket>0){
                System.out.println(Thread.currentThread().getName()+"买了第"+ticket+"张票");
                ticket--;
            }
        }
    }
}

使用Lock锁

Lock是一个接口,实现类是ReentrantLock。
通过两个方法:Lock() 获取锁、unlock() 释放锁

public class MyTicket implements Runnable{
    int ticket = 100;//定义100张票
    Lock lock = new ReentrantLock(); //创建Lock对象
    @Override
    public void run() {
        while(true){
            try {
                
                lock.lock(); //获取锁
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");
                    ticket--;
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }finally {
                lock.unlock();//释放锁
            }
        }
    }
}
public class Test {
    public static void main(String[] args) {
        MyTicket myTicket = new MyTicket();
        Thread t1 = new Thread(myTicket, "张三");
        Thread t2 = new Thread(myTicket, "李四");
        t1.start();
        t2.start();
    }
}

通过synchronized实现同步代码块或方法和通过Lock解决线程不安全的区别

synchronized不管是同步代码块还是同步方法,都需要在结束一对{}之后,释放锁对象。而Lock是通过两个方法控制需要被同步的代码,更灵活。

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

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

相关文章

深度解析:当下流行的人工智能大模型生成逻辑

在过去的几年里,人工智能领域经历了前所未有的革新,其中最引人注目的就是大规模预训练模型的崛起。这些模型,如GPT系列、BERT、T5、DALLE和CLIP等,凭借其强大的语言理解和生成能力,已经在自然语言处理(NLP&…

ctfshow(web入门-信息搜集)

1.web1 直接F12查看即可 2.web2 根据提示使用抓包工具 3.web3 根据提示使用burp抓包,然后参数使用repeater模块进行发送 4.web4 根据提示先访问robots 5.web5 6.web6 使用dirsearch 即可www.zip 7.web7 8.web8 9.web9 10. web10 11.web11 12.web12 根据提示在底…

wordpress的restfull API使用教程,之如何用postman调试API,以便能使用vue等前端框架开发主题

文章目录 API开发手册在postman中调试这里以 post 一篇文章为例,讲解如何调试: 步骤 1:生成应用密码步骤 2:配置Postman步骤 3:创建文章 参考链接 API开发手册 官方API手册:https://developer.wordpress.o…

京东技术团队撰写的整整986页《漫画学Python》到底有什么魅力?

这是一本Python入门书。无论您是想学习编程的小学生,还是想参加计算机竞赛的中学生,抑或是计算机相关专业的大学生,甚至是正在从事软件开发的职场人,本书都适合您阅读和学习。但您若想更深入地学习Python并进行深层次应用&#xf…

07.C2W2.Part-of-Speech (POS) Tagging and Hidden Markov Models

往期文章请点这里 目录 OverviewPart of Speech TaggingMarkov ChainsMarkov Chains and POS TagsPOS tags as StatesTransition probabilitiesThe transition matrixInitial probabilities Hidden Markov ModelsEmission probabilitiesSummary Calculating ProbabilitiesTran…

【实习问题记录】Nodeclub本地部署

问题描述 在按照官方网站给出的教程一步一步操作以后发现出现以下报错: 问题分析 显示连接不上mongodb,分析报错可能是因为版本不匹配导致的,查看安装的mongodb版本发现是7.0.4,与目标版本不匹配,同时查看mongodb官…

C#写的winform项目无法打包发布?谈谈思路

🏆本文收录于「Bug调优」专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&…

一款简单、免费的web文件共享服务器

#共享文件# #远程访问# #手机访问# 文件共享已成为我们日常生活和工作中不可或缺的一部分。它如同一条无形的纽带,将人们紧密地联系在一起,促进了信息的快速传播和交流。 文件共享的魅力在于其打破了地域和时间的限制。无论我们身处世界的哪个角落&…

Leetcode2542-最大子序列的分数

1.问题转换 首先明确题意,要选取的值和num1,num2两个数组都有关,但是num1中选取的是k个数,num2中选取的是1个数,显然num2中的数所占的权重较大(对结果影响较大),所以我们就可以对nu…

猫咪浮毛满天飞怎么办?希喂、352、米家养猫空气净化器对比测试

作为一名资深铲屎官,表现掉毛季又来了,猫咪的毛发满天飞,怎么办?我家里的猫咪一到换毛季就掉满地的毛发,尤其喜欢在家里奔跑打闹,结果整个房间都是毛。家里的猫掉毛特别严重,感觉随便咳两下就能…

前端web在线PPT编辑器-PPTLIST

哈喽,大家好,今天给大家介绍一款的在线的PPT编辑器开源框架-PPTLIST;他是一个基于 Vue3.x TypeScript 的在线演示文稿(幻灯片)应用,还原了大部分 Office PowerPoint 常用功能,支持 文字、图片、…

[FBCTF2019]RCEService

[FBCTF2019]RCEService 绕过正则 随便输一下Json格式的东西 发现了get方式的cmd参数 然后{"cmd":"ls /"}没回显应该是被过滤了 {"cmd":"ls"}正则函数preg_match只能匹配第一行 Linux中cat命令实际是在bin中 ?cmd{%0a"cmd&quo…

微信小程序开发-003-首页(轮播图,状态栏,导航栏)

哈喽小伙伴们大家好,我是程序媛小李,今天,我们继续来开发微信小程序. 在这里,先贴上首页的效果图: 整个页面大概可以分为顶部的状态栏区域,轮播图区域,公司信息区域,商品导航区域,商品推荐区域,以及最下面的导航栏区域. 一,底部导航栏 在这里,我们遵循从外到内的原则,我们先来…

【力扣: 15题: 三数之和】

15题: 三数之和 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意: 答案中不可以包含重复的三元组。 …

回归损失和分类损失

回归损失和分类损失是机器学习模型训练过程中常用的两类损失函数,分别适用于回归任务和分类任务。 回归损失函数 回归任务的目标是预测一个连续值,因此回归损失函数衡量预测值与真实值之间的差异。常见的回归损失函数有: 均方误差&#xff…

参考人物和背景生成惊艳图片,comfyui风格工作流!

前言 轻松使用ComfyUI生成惊艳图片:快速指南 在这篇文章中,我们将分享如何使用ComfyUI工作流轻松生成高质量的图像。这一过程不仅适合专业的设计师,同样也适用于刚开始接触图像生成技术的用户。通过本文,你将了解如何利用ComfyU…

CSS--表格自适应宽度并设置最小宽度

原文网址&#xff1a;CSS--表格自适应宽度并设置最小宽度_IT利刃出鞘的博客、-CSDN博客 简介 本文介绍怎样让HTML的表格自适应宽度。 Java技术星球&#xff1a;way2j.com 问题描述 默认样式下&#xff0c;表格会出现某一列很窄的情况&#xff1a; 代码&#xff1a; <h…

Function Call ReACT,Agent应用落地的加速器_qwen的function calling和react有什么不同

探索智能体Agent的未来之路&#xff1a;Function Call与ReACT框架的较量&#xff0c;谁能引领未来&#xff1f; 引言 各大平台出现智能体应用创建&#xff0c;智能体逐渐落地&#xff0c;背后的使用哪种框架&#xff1f; 随着各大平台&#xff0c;例如百度千帆APPbuilder、阿…

Python入门 2024/7/8

目录 数据容器 dict(字典&#xff0c;映射) 语法 定义字典字面量 定义字典变量 定义空字典 从字典中基于key获取value 字典的嵌套 字典的常用操作 新增元素 更新元素 删除元素 清空字典 获取全部的key 遍历字典 统计字典内的元素数量 练习 数据容器的通用操作…

浏览器控制台打印日志的方法汇总

目录 console.table用法 打印数组 打印对象 打印数组对象 打印数组对象里的指定字段 console.count用法 不传参打印 传参打印 console.warn用法 打印文本 打印对象 console.error用法 打印文本 打印对象 console.assert用法 打印文本 打印对象 consol…