Java线程安全

article/2025/9/14 8:12:46

前段时间有测试一个后端对账单和话单采集服务,在测试过程中有涉及到数据库读写逻辑和并发的场景,所以结合经验针对系统技术架构设计了部分并发场景结合数据库读写时可能出现的一些问题的用例,也确实出现了一些测试环境容易忽视,线上环境确确实实可能出现的问题,当然最后还是得到了妥善的解决.下面说说后端测试应该考虑的一些线程安全和数据读写方面的问题.

前提:测试环境的架构尽量向线上环境的架构靠拢,比如线上如果采用分布式集群,测试环境如果是单机,那么部分问题自然无法暴露,如果测试环境无足够资源模拟线上的几十台集群环境,那么我们采用3~4台资源来模拟集群,也不是不可以.

1.线程安全

什么是线程安全?

        线程安全就是保证多个线程同时对某一对象或资源进行操作时不会出错.比如我们购物,下订单前某商品库存数为2,两个用户同时对该商品进行下单购买,系统会记录商品库存总数,如果不加以并发控制,那么就会出现某个用户对当前库存总数的脏读的情况.

        线程安全问题出现的3个必要条件:

        1.多线程环境

        2.多线程共享同一资源

        3.对资源进行非原子性操作

示例:

 上图是利用TestNG实现并发,效果为10个线程执行100个操作,控制台输出中可以看到前9个的号码都是15100000000,这里就有线程安全的问题,10个线程最开始会同时读取第一个号码资源,读取到的都是15100000000,所以执行的都是这个号码,然后才会递增.那么我们通过干预各线程之间对资源的操作来解决这种问题.

保证线程安全的常用方法:

        1.Synchronized:保证方法内部或代码块内部资源或数据的互斥访问(哪里需要Synchronized加哪里).达到某资源在同一时间最多只能有一个线程访问的效果.

        2.java.util.concurrent.atomic:提供一列类,包括:AtomicBoolean,AtomicInteger,AtomicLong类,使用这些类来声明变量或资源时可以保证对其操作时具有原子性,以此达到线程安全的效果.

 适用场景:数据流转逻辑多,逻辑复杂,中间件较多的逻辑都需要考虑并发场景的测试.

 例如,测试话单采集服务的时候,有一个逻辑为生成的话单要从A平台经数据清洗后传递到B平台,A平台的话单原单和清洗处理后的话单数据都要利用mq(消息队列,消息中间件,实现各模块数据存取速度不一致的问题,达到各模块解耦的效果),利用脚本实现B平台在消费mq中消息时,如果话单数据较多会出现消费速度忽快忽慢的情况,后面经定位为并发情况下,生产了大量消息在消息队列中,逻辑中采用了将所有消息数据都加载进内存,造成了内存吃紧,处理慢的情况.如果仅仅是功能测试,是发现不了此问题的,但是线上会真正暴露的问题.

2.数据库锁:

        系统性能为题,如果定位到是数据库性能瓶颈,可能很大一部分原因都是因为索引的问题.例如:

        以mysql为例,就存在行锁定表锁定以及事务中的死锁.

事务中的死锁:事务都遵从ACID特性,即原子性,一致性,持久性,隔离性.如果两个事务都持有对方需要的数据,并且都在等待对方释放锁,就会出现死锁的情况(B态度:A放我才放,A态度:B放我才放). 

行锁定:我们在update更新/delete删除某行数据时,mysql会自动添加排它锁,即行锁定,update和delete某行数据时,如果where条件中的字段存在未添加索引的情况,mysql就会自动将行锁定升级为表锁定(行锁定时,其他逻辑操作无法操作该行数据,表锁定时,其他逻辑无法操作该整张表).

拿遇到过的一个bug举例:混合场景下,有的用户会读取某行数据是否存在,不存在的话会插入数据;有的用户会写入更新某行数据,利用多线程实现并发场景时,某用户写入更新数据时因为检索条件中的字段未加合适的索引,mysql会自动将行级锁定升级为表级锁定,导致整张表被锁定,线程中那些做插入数据的操作就会失败,导致大量报错.所以,业务逻辑中如果存在多个逻辑同时处理某个表的数据,就需要考虑这些逻辑并行处理的场景.


http://chatgpt.dhexx.cn/article/vUpuC5Fq.shtml

相关文章

线程安全之 - ThreadLocal

ThreadLocal的底层原理 ThreadLocal是Java中所提供的线程本地存储机制(线程内共享),可以利⽤该机制将数据缓存在某个线程内部, 该线程可以在任意时刻、任意⽅法中获取缓存的数据;ThreadLocal底层是通过ThreadLocalMap…

线程锁(ReentrantLock、synchronized)为何不能用作分布式锁

为什么使用分布式锁 分布式锁实现目前有三种: 数据库乐观锁;ZooKeeper的分布式锁;Redis的分布式锁; 在以前单体架构Web应用场景下,我们可以使用ReentrantLock或synchronized进行上锁,保证资源安全,现如今大…

Redis分布式锁真的安全吗?

大家好,今天我们来聊一聊Redis分布式锁。 首先大家可以先思考一个简单的问题,为什么要使用分布式锁?普通的jvm锁为什么不可以? 这个时候,大家肯定会吧啦吧啦想到一堆,例如java应用属于进程级,…

ThreadLocal能解决线程安全问题?胡扯!本文教你正确的使用姿势【享学Java】

跟对领导很重要:愿意教你的,并且放手让你做的领导要珍惜。 目录 前言正文ThreadLocal是什么?ThreadLocal怎么用?局限性InheritableThreadLocal向子线程传递数据开源框架使用示例 ThreadLocal不能解决共享变量的线程安全问题Thread…

Java线程安全详细总结

以下是我的PPT文档,不知道怎么复制到博客,只能一个一个插入图片发上来了。感觉总结的不错,分享一下。 文档地址:http://download.csdn.net/detail/csujiangyu/9526641

分布式系统详解--基础知识(线程)

分布式系统详解--基础知识(线程) 一、导读 前面跟大家讲了一下 分布式系统详解--基础知识(概论) ,可以稍微了解一下大体上分布式是怎么一回事了。这片篇文章主要是讲述一下线程的问题分别介绍一下,什么线…

分布式项目线程安全问题(电商扣减库存的安全问题1)

电商减库存存在的安全问题 Override public void deductStock(Map<Long, Integer> skuMap) {for (Map.Entry<Long, Integer> entry : skuMap.entrySet()) {Long skuId entry.getKey();Integer num entry.getValue();// 查询skuSku sku getById(skuId);// 判断…

分布式项目中 如何保证线程安全问题?-------ZooKeeper

前沿&#xff1a; 上篇文章我们聊到了在解决分布式项目中线程安全问题&#xff0c;提到解决方案还有其他的&#xff0c;那么在此提出 基于 zookeeper 解决分布式项目中的线程安全问题 也是目前市面上比较流行的。做为一个高级开发工程师也是必须要学习的。 ZooKeeper是什么东…

分布式线程安全(redis、zookeeper、数据库)

https://blog.csdn.net/u010963948/article/details/79006572 Q:一个业务服务器&#xff0c;一个数据库&#xff0c;操作&#xff1a;查询用户当前余额&#xff0c;扣除当前余额的3%作为手续费 synchronized lock db lock Q&#xff1a;两个业务服务器&#xff0c;一个数据库&…

分布式集群中如何保证线程安全?

目录 分布式集群中的线程安全问题 解决方法 串行化 分布式锁 Redis如何实现呢&#xff1f; 问题&#xff1a;setnx刚好获取到锁&#xff0c;业务逻辑出现异常&#xff0c;导致锁无法释放 问题&#xff1a;可能会释放其他服务器的锁。 问题&#xff1a;删除操作缺乏原子…

java outlook 发送邮件_基于java使用JavaMail发送邮件

一、邮件的相关概念 邮件协议。主要包括&#xff1a; SMTP协议&#xff1a;Simple Mail Transfer Protocol&#xff0c;即简单邮件传输协议&#xff0c;用于发送电子邮件 POP3协议&#xff1a;Post Office Protocol 3&#xff0c;即邮局协议的第三个版本&#xff0c;用于接收邮…

java 发邮件(有正文,有图片,有附件)

一 需求: 1 java实现邮件发送 2 发送内容: ① 正文: 图片说明和图片 ② 附件一: 图片作为附件发送 ③ 附件二: Excel表格 二 思路: 1首先创建一个 Java 工程&#xff0c;把下载好的 javax.mail.jar 作为类库加入工程 2邮件创建步骤: 配置连接邮件服务器的参数( 邮件服务器SM…

java接收邮件_Java实现邮件收发

一. 准备工作 1. 传输协议 SMTP协议-->发送邮件: 我们通常把处理用户smtp请求(邮件发送请求)的服务器称之为SMTP服务器(邮件发送服务器) POP3协议-->接收邮件: 我们通常把处理用户pop3请求(邮件接收请求)的服务器称之为POP3服务器(邮件接收服务器) 2. 邮件收发原理 闪电…

java发送邮件工具类

1. 普通java实现邮件发送 1.1 创建maven项目&#xff0c;配置pom.xml文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance&qu…

java发送邮件带附件

一、 开启SMTP服务 1.基本都在邮箱设置里&#xff0c;开启后会获得神秘代码&#xff0c;后面有用。 2.记得添加依赖&#xff0c;或者自己添加jar包。 <dependency><groupId>javax.mail</groupId><artifactId>mail</artifactId><version>…

java 邮件模板

邮件发送代码可参照 java 发送邮件 1.情形 邮件发送代码可参照上述&#xff0c;本例只说明如果读取模板文件。公司定义模板较为复杂的情况&#xff0c;可采用此类发送方式 2. 模板 2.1 resource 建立模板 2.2 ftl 模板如下 <p>您好&#xff0c;${name}&#xff0c;您…

使用JAVA实现邮件发送功能

一、准备工作 小编今天以 QQ邮箱 进行演示操作。 想要使用代码操作邮箱发送邮件&#xff0c;需要在邮箱设置中申请开通 POP3/SMTP 服务。 接下来跟着小编的图文一步一步的操作开通吧&#xff01; 1.1 登录网页QQ邮箱&#xff0c;点击页面顶部设置按钮。 1.2 点击后会打开邮箱…

java发送qq邮件

1.登录qq邮箱 1&#xff09;点击设置 2&#xff09;点击账户 3&#xff09;开启第一个服务&#xff0c;我已经开过了 4&#xff09;开启验证&#xff08;让你发送指定内容到某个号码&#xff09;&#xff0c;完成后点击我已发送&#xff0c;就会出现授权码&#xff0c;授权码很…

java实现邮件发送

一.第一步:导入两个jar包。 activation.jar 和 mail.jar, 一定要添加到构建路径(不然找不到包) 两个用于Java发送邮件的jar包-Java文档类资源-CSDN下载 二、创建邮箱工具类:Mail.java import java.util.*; import java.io.*; import javax.mail.*; import javax.m…

Java(81):Java发邮件简单示例

Java Email jar包下载地址&#xff1a;JavaMail API https://www.oracle.com/java/technologies/javamail.html JavaMail 右侧下载&#xff0c;选择jar包下载 API文档参考&#xff1a;JavaMail API documentation https://javaee.github.io/javamail/docs/api/ 或直接引用…