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

线程不安全问题

日常生活中我们会经常碰到在不同的平台上买各种票的问题,例如在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是通过两个方法控制需要被同步的代码,更灵活。

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

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

相关文章

2024最新版若依-RuoYi-Vue3-PostgreSQL前后端分离项目部署手册教程

项目简介: RuoYi-Vue3-PostgreSQL 是一个基于 RuoYi-Vue3 框架并集成 PostgreSQL 数据库的项目。该项目提供了一套高效的前后端分离的开发解决方案,适用于中小型企业快速构建现代化的企业级应用。此项目结合了 RuoYi-Vue-Postgresql 和 RuoYi-Vue3 的优点&#xff0…

libaom 编码器实验 AV1 标准 SVC 分层编码

SVC编码 视频SVC编码,即Scalable Video Coding(可适性视讯编码或可分级视频编码),是H.264/MPEG-4 AVC编码的一种扩展,它提供了更大的编码弹性,并且具有时间可适性(Temporal Scalability&#x…

React Hooks:上天在提醒你,别再用Class组件了!

React Hooks:上天在提醒你,别再用Class组件了! React Hooks 的出现可以说是前端界的一场革命。它不仅让我们告别了繁琐的 Class 组件,还让代码变得更加简洁、易读、易维护。如果你还在固守 Class 组件的阵地,那么这篇…

vue3项目实战中的接口调用

vue项目组成 一个项目往往由这几个部分组成。👇👇 其中在src文件夹中的内容如下👇👇 我们常常将接口文件,新建在文件夹src下,一般命名为api,api内的文件便是接口文件。👇&#x1f4…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第一篇 嵌入式Linux入门篇-

i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

OpenCV基础(2)

目录 滤波处理 均值滤波 基本原理 函数用法 程序示例 高斯滤波 基本原理 函数用法 程序示例 中值滤波 基本原理 函数用法 程序示例 形态学 腐蚀 膨胀 通用形态学函数 前言:本部分是上一篇文章的延续,前面部分请查看:OpenCV…

MyBatis的底层机制

手写MyBatis底层机制 读取配置文件,得到数据库连接 思路 引入必要的依赖需要写一个自己的config.xml文件,在里面配置一些信息,driver,url ,password,username需要编写Configuration类,对 自己…

服务器数据恢复—同品牌不同系列服务器raid5阵列数据恢复方案分析

RAID5磁盘阵列数据恢复案例一: 服务器数据恢复环境: 一台某品牌LH6000系列服务器,通过NetRaid阵列卡将4块硬盘组建为一组RAID5磁盘阵列。操作系统都为Window server,数据库是SQLServer。 服务器故障: LH6000系列服务器…

四、嵌入式技术(考点篇)试题(1)

我选择C,实际答案选B,答案给出的理由是,SoC是片上系统,包含完整系统和嵌入式软件全部内容,B的说法有点片面。 明显选C,嵌入式跟通用性不太沾边。 嵌入式OS特征:裁剪配置安全可靠实时高确定&…

Python基础知识——(001)

文章目录 P4——3. 程序设计语言的分类 1. 程序设计语言 2. 编译与解释 P5——4. Python语言的简介与开发工具 1. Python语言的简介 2. Python语言的发展 3. Python语言的特点 4. Python的应用领域 5. Python的开发工具 P6——5. IPO编程方式 IPO程序编写方法 P7——6. print函…

大模型隐私窃取攻击

前言 对于大模型风险,目前大家更多关注的还是越狱攻击。隐私这一块,可能国内还不如欧美重视,在安全的学术四大会议论文中,有时候甚至AI隐私的论文比AI安全的论文更多。但实际上,除了越狱之外,另外一大风险…

监控电脑软件【2024最新】|6款软件保姆式解析!

在数字化办公日益普及的今天,很多企业为了更好的提升员工的工作效率和保障企业的数据安全,开始给自己的企业布局电脑监控软件。 但市面上的电脑监控软件种类繁多复杂,为了更好的保障企业利用,小编推荐了以下几款电脑监控软件供大…

阶段三:项目开发---大数据开发运行环境搭建:任务4:安装配置Spark集群

任务描述 知识点:安装配置Spark 重 点: 安装配置Spark 难 点:无 内 容: Apache Spark 是专为大规模数据处理而设计的快速通用的计算引擎。Spark是UC Berkeley AMP lab (加州大学伯克利分校的AMP实验室)所开源的类Hadoop …

Python自动化测试系列[v1.0.0][高效自动化设计]

Python多线程应用于自动化测试 将多线程在测试巧妙地应用,确实会带来很多好处,并且这是充分利用机器资源执行高效率测试很好的方式 # -*- coding: utf-8 -*- import threading from time import ctime import time from selenium import webdriverdef …

【c语言】玩转文件操作

🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:C语言 目录 引言 一、文件的打开和关闭 1.流 2.标准流 3.文本文件和二进制文件 4.控制文件打开与关闭的函数 二、文件的顺序读写 三、文件的随机读写 1…

7月学术会议:7月可投的EI国际会议

随着科技的迅猛发展,学术交流与研讨成为了推动科研进步的重要途径。进入7月,众多高质量的EI国际会议纷纷拉开帷幕,为全球的科研工作者提供了一个展示研究成果、交流学术思想的平台。以下,我们将详细介绍一些在7月可投的EI国际会议…

Java集合升序降序、转Set的方法

Collections.sort(list,Comparator.comparing(OcApplySquareVo::getApplyName).reversed()); 集合转set /** 集合转set */Set<String> pkCodeSet rows.stream().map(RailwayWeighBookResult.RailwayWeighBook::getPkCode).collect(Collectors.toSet());

猫咪浮毛太多怎么处理?6年铲屎官最值得买的猫毛空气净化器分享

作为一位拥有6年铲屎经验的铲屎官&#xff0c;家中既有宝宝又有毛孩子的铲屎官家庭来说&#xff0c;空气中的宠物异味和猫毛不仅影响生活质量&#xff0c;更关乎家人的健康。普通空气净化器虽然能够提供基本的空气净化&#xff0c;但对于养猫家庭的特定需求&#xff0c;如去除宠…

Pytest单元测试系列[v1.0.0][Pytest基础]

Pytest安装与配置 和Unittest一样&#xff0c;Pytest是另一个Python语言的单元测试框架&#xff0c;与Unittest相比它的测试用例更加容易编写、运行方式更加灵活、报错信息更加清晰、断言写法更简洁并且它可以运行有unittest和nose编写的测试用例。 Pytest 安装 启动命令行&…

A股本周在3000点以下继续筑底,本周依然继续探底?

夜已深&#xff0c;市场传来了3个浓烈的消息&#xff0c;炸锅了&#xff0c;恐有大事发生&#xff0c;马上告诉所有人&#xff1a; 消息面&#xff1a; 1、中国经济周刊首席评论员钮文新称&#xff1a;不要等中小投资者都彻底希望&#xff0c;销户离场了&#xff0c;才发现该…